Esempio n. 1
0
int
set_node_name(int argc, char **argv)
{
	iscsid_set_node_name_req_t req;
	iscsid_response_t *rsp;
	uint64_t isid;

	memset(&req, 0x0, sizeof(req));
	if (!cl_get_string('n', (char *)req.InitiatorName, argc, argv)) {
		arg_missing("Initiator Name");
	}
	cl_get_string('A', (char *)req.InitiatorAlias, argc, argv);
	isid = cl_get_longlong('i', argc, argv);
	hton6(req.ISID, isid);

	check_extra_args(argc, argv);

	send_request(ISCSID_SET_NODE_NAME, sizeof(req), &req);

	rsp = get_response(FALSE);
	if (rsp->status) {
		status_error(rsp->status);
	}
	free_response(rsp);

	printf("OK\n");
	return 0;
}
Esempio n. 2
0
enum cib_errors 
cib_process_shutdown_req(
	const char *op, int options, const char *section, crm_data_t *input,
	crm_data_t *existing_cib, crm_data_t **result_cib, crm_data_t **answer)
{
	enum cib_errors result = cib_ok;
	const char *host = cl_get_string(input, F_ORIG);
	
	*answer = NULL;

	if(cl_get_string(input, F_CIB_ISREPLY) == NULL) {
		crm_info("Shutdown REQ from %s", host);
		return cib_ok;

	} else if(cib_shutdown_flag) {
		crm_info("Shutdown ACK from %s", host);
		terminate_ha_connection(__FUNCTION__);
		return cib_ok;

	} else {
		crm_err("Shutdown ACK from %s - not shutting down",host);
		result = cib_unknown;
	}
	
	return result;
}
Esempio n. 3
0
int
remove_isns_server(int argc, char **argv)
{
	iscsid_sym_id_t req;
	iscsid_search_list_req_t srch;
	iscsid_response_t *rsp;

	if (!cl_get_id('I', &req, argc, argv)) {
		if (!cl_get_string('a', (char *)srch.strval, argc, argv)) {
			arg_missing("Server Address");
		}
		check_extra_args(argc, argv);
		srch.search_kind = FIND_ADDRESS;
		srch.list_kind = ISNS_LIST;

		send_request(ISCSID_SEARCH_LIST, sizeof(srch), &srch);
		rsp = get_response(FALSE);
		if (rsp->status) {
			status_error_slist(rsp->status);
		}
		GET_SYM_ID(req.id, rsp->parameter);
		free_response(rsp);
	} else {
		check_extra_args(argc, argv);
	}
	send_request(ISCSID_REMOVE_ISNS_SERVER, sizeof(req), &req);
	rsp = get_response(TRUE);
	if (rsp->status) {
		status_error(rsp->status);
	}
	free_response(rsp);

	printf("OK\n");
	return 0;
}
Esempio n. 4
0
int
add_initiator(int argc, char **argv)
{
	iscsid_add_initiator_req_t req;
	iscsid_add_initiator_rsp_t *res;
	iscsid_response_t *rsp;

	memset(&req, 0x0, sizeof(req));
	if (!cl_get_string('a', (char *)req.address, argc, argv)) {
		arg_missing("Interface Address");
	}
	cl_get_symname(req.name, argc, argv);
	check_extra_args(argc, argv);

	send_request(ISCSID_ADD_INITIATOR_PORTAL, sizeof(req), &req);
	rsp = get_response(FALSE);
	if (rsp->status) {
		status_error(rsp->status);
	}
	res = (iscsid_add_initiator_rsp_t *)(void *)rsp->parameter;
	printf("Added Initiator Portal %d\n", res->portal_id);

	free_response(rsp);
	return 0;
}
Esempio n. 5
0
xmlNode *
convert_ha_message(xmlNode * parent, HA_Message * msg, const char *field)
{
    int lpc = 0;
    xmlNode *child = NULL;
    const char *tag = NULL;

    CRM_CHECK(msg != NULL, crm_err("Empty message for %s", field);
              return parent);

    tag = cl_get_string(msg, F_XML_TAGNAME);
    if (tag == NULL) {
        tag = field;

    } else if (parent && safe_str_neq(field, tag)) {
        /* For compatibility with 0.6.x */
        crm_debug("Creating intermediate parent %s between %s and %s", field,
                  crm_element_name(parent), tag);
        parent = create_xml_node(parent, field);
    }

    if (parent == NULL) {
        parent = create_xml_node(NULL, tag);
        child = parent;

    } else {
        child = create_xml_node(parent, tag);
    }

    for (lpc = 0; lpc < msg->nfields; lpc++) {
        convert_ha_field(child, msg, lpc);
    }

    return parent;
}
Esempio n. 6
0
void
cib_pre_notify(
	int options, const char *op, crm_data_t *existing, crm_data_t *update) 
{
	HA_Message *update_msg = NULL;
	const char *type = NULL;
	const char *id = NULL;

	update_msg = ha_msg_new(6);

	if(update != NULL) {
		id = crm_element_value(update, XML_ATTR_ID);
	}
	
	ha_msg_add(update_msg, F_TYPE, T_CIB_NOTIFY);
	ha_msg_add(update_msg, F_SUBTYPE, T_CIB_PRE_NOTIFY);
	ha_msg_add(update_msg, F_CIB_OPERATION, op);

	if(id != NULL) {
		ha_msg_add(update_msg, F_CIB_OBJID, id);
	}

	if(update != NULL) {
		ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(update));
	} else if(existing != NULL) {
		ha_msg_add(update_msg, F_CIB_OBJTYPE, crm_element_name(existing));
	}

	type = cl_get_string(update_msg, F_CIB_OBJTYPE);	
	attach_cib_generation(update_msg, "cib_generation", the_cib);
	
	if(existing != NULL) {
		add_message_xml(update_msg, F_CIB_EXISTING, existing);
	}
	if(update != NULL) {
		add_message_xml(update_msg, F_CIB_UPDATE, update);
	}

	g_hash_table_foreach(client_list, cib_notify_client, update_msg);
	
	if(update == NULL) {
		crm_debug_2("Performing operation %s (on section=%s)",
			    op, type);

	} else {
		crm_debug_2("Performing %s on <%s%s%s>",
			    op, type, id?" id=":"", id?id:"");
	}
		
	crm_msg_del(update_msg);
}
Esempio n. 7
0
static int
authenticate_with_cookie(IPC_Channel *chan, cl_uuid_t *cookie) 
{
	struct ha_msg *	request;
	struct ha_msg * reply;

	assert(chan != NULL);
	assert(cookie != NULL);

	if (!(request = create_basic_reqmsg_fields(ST_SIGNON))) {
		return ST_FAIL;
	}
	if (ha_msg_adduuid(request, F_STONITHD_COOKIE, cookie) != HA_OK) {
		stdlib_log(LOG_ERR, "cannot add field to ha_msg.");
		ZAPMSG(request);
		return ST_FAIL;
	}

	/* Send request/read response */
	if (send_request(chan, request, DEFAULT_TIMEOUT) != ST_OK) {
		ZAPMSG(request);
		return ST_FAIL;
	}
	ZAPMSG(request);

	if (!(reply = recv_response(chan, DEFAULT_TIMEOUT))) {
		return ST_FAIL;
	}
	
	/* Are we signed on this time? */
	if ( TRUE == is_expected_msg(reply, F_STONITHD_TYPE, ST_APIRPL, 
			     F_STONITHD_APIRPL, ST_RSIGNON, TRUE) ) {
		if ( !STRNCMP_CONST(
			cl_get_string(reply,F_STONITHD_APIRET), ST_APIOK) ) {
			ZAPMSG(reply);
			return ST_OK;
		}
	}

	ZAPMSG(reply);
	return ST_FAIL;
}
Esempio n. 8
0
static gboolean 
cmp_field(const struct ha_msg * msg,  
		const char * field_name, const char * field_content,
		gboolean mandatory)
{
	const char * tmpstr;

	tmpstr = cl_get_string(msg, field_name);
	if ( tmpstr && strncmp(tmpstr, field_content, 80) == 0 ) {
		return TRUE;
	} else {
		stdlib_log(mandatory ? LOG_ERR : LOG_NOTICE
			, "field <%s> content is "
			" <%s>, expected content is: <%s>"
			, field_name
			, (NULL == tmpstr) ? "NULL" : tmpstr
			, field_content);
		return FALSE;
	}
}
Esempio n. 9
0
static void
general_struct_display(int log_level, int seq, char* name, void* value, int vlen, int type)
{
	int slen;
	int netslen;

	HA_MSG_ASSERT(name);
	HA_MSG_ASSERT(value);	
	
	slen = fieldtypefuncs[type].stringlen(strlen(name), vlen, value);
	netslen = fieldtypefuncs[type].netstringlen(strlen(name), vlen, value);
	
	cl_log(log_level, "MSG[%d] : [(%s)%s=%p(%d %d)]",
	       seq,	FT_strings[type],
	       name,	value, slen, netslen);
	if(cl_get_string((struct ha_msg*) value, F_XML_TAGNAME) == NULL) {
		cl_log_message(log_level, (struct ha_msg*) value);
	} else {
		/* use a more friendly output format for nested messages */
		struct_display_as_xml(log_level, 0, value, NULL, TRUE);
	}
}
Esempio n. 10
0
STATIC int
do_remove_target(int argc, char **argv, iscsid_list_kind_t kind)
{
	iscsid_list_id_t req;
	iscsid_search_list_req_t srch;
	iscsid_response_t *rsp;

	if (!cl_get_id('I', &req.id, argc, argv)) {
		if (!cl_get_string('n', (char *)srch.strval, argc, argv)) {
			arg_missing("Target ID or Name");
		}
		check_extra_args(argc, argv);

		srch.search_kind = FIND_TARGET_NAME;
		srch.list_kind = kind;

		send_request(ISCSID_SEARCH_LIST, sizeof(srch), &srch);
		rsp = get_response(FALSE);
		if (rsp->status) {
			status_error_slist(rsp->status);
		}
		GET_SYM_ID(req.id.id, rsp->parameter);
		free_response(rsp);
	} else {
		check_extra_args(argc, argv);
	}
	req.list_kind = kind;
	send_request(ISCSID_REMOVE_TARGET, sizeof(req), &req);
	rsp = get_response(TRUE);
	if (rsp->status) {
		status_error(rsp->status);
	}
	free_response(rsp);
	printf("OK\n");
	return 0;
}
Esempio n. 11
0
void
te_update_diff(const char *event, HA_Message *msg)
{
	int rc = -1;
	const char *op = NULL;
	crm_data_t *diff = NULL;
	crm_data_t *aborted = NULL;
	const char *set_name = NULL;

	int diff_add_updates = 0;
	int diff_add_epoch  = 0;
	int diff_add_admin_epoch = 0;

	int diff_del_updates = 0;
	int diff_del_epoch  = 0;
	int diff_del_admin_epoch = 0;
	
	if(msg == NULL) {
		crm_err("NULL update");
		return;
	}		

	ha_msg_value_int(msg, F_CIB_RC, &rc);	
	op = cl_get_string(msg, F_CIB_OPERATION);

	if(rc < cib_ok) {
		crm_debug_2("Ignoring failed %s operation: %s",
			    op, cib_error2string(rc));
		return;
	} 	

	diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);

	cib_diff_version_details(
		diff,
		&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates, 
		&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
	
	crm_debug("Processing diff (%s): %d.%d.%d -> %d.%d.%d", op,
		  diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
		  diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
	log_cib_diff(LOG_DEBUG_2, diff, op);

	set_name = "diff-added";
	if(diff != NULL) {
		crm_data_t *section = NULL;
		crm_data_t *change_set = find_xml_node(diff, set_name, FALSE);
		change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE);

		if(change_set != NULL) {
			crm_debug_2("Checking status changes");
			section=get_object_root(XML_CIB_TAG_STATUS,change_set);
		}
		
		if(section != NULL) {
			extract_event(section);
		}
		crm_debug_2("Checking change set: %s", set_name);
		aborted = need_abort(change_set);
	}
	
	set_name = "diff-removed";
	if(diff != NULL && aborted == NULL) {
		crm_data_t *attrs = NULL;
		crm_data_t *status = NULL;
		crm_data_t *change_set = find_xml_node(diff, set_name, FALSE);
		change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE);

		crm_debug_2("Checking change set: %s", set_name);
		aborted = need_abort(change_set);		

		if(aborted == NULL && change_set != NULL) {
			status = get_object_root(XML_CIB_TAG_STATUS, change_set);
		
			xml_child_iter_filter(
				status, node_state, XML_CIB_TAG_STATE,
				
				attrs = find_xml_node(
					node_state, XML_TAG_TRANSIENT_NODEATTRS, FALSE);
				
				if(attrs != NULL) {
					crm_info("Aborting on "XML_TAG_TRANSIENT_NODEATTRS" deletions");
					abort_transition(INFINITY, tg_restart,
							 XML_TAG_TRANSIENT_NODEATTRS, attrs);
				}
				);
Esempio n. 12
0
void
cib_notify_client(gpointer key, gpointer value, gpointer user_data)
{

	IPC_Channel *ipc_client = NULL;
	HA_Message *update_msg = user_data;
	cib_client_t *client = value;
	const char *type = NULL;
	gboolean is_pre = FALSE;
	gboolean is_post = FALSE;	
	gboolean is_confirm = FALSE;
	gboolean is_replace = FALSE;
	gboolean is_diff = FALSE;
	gboolean do_send = FALSE;

	int qlen = 0;
	int max_qlen = 0;
	
	CRM_DEV_ASSERT(client != NULL);
	CRM_DEV_ASSERT(update_msg != NULL);

	type = cl_get_string(update_msg, F_SUBTYPE);
	CRM_DEV_ASSERT(type != NULL);

	if(client == NULL) {
		crm_warn("Skipping NULL client");
		return;

	} else if(client->channel == NULL) {
		crm_warn("Skipping client with NULL channel");
		return;

	} else if(client->name == NULL) {
		crm_debug_2("Skipping unnammed client / comamnd channel");
		return;
	}
	
	if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
		is_pre = TRUE;
		
	} else if(safe_str_eq(type, T_CIB_POST_NOTIFY)) {
		is_post = TRUE;

	} else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
		is_confirm = TRUE;

	} else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
		is_diff = TRUE;

	} else if(safe_str_eq(type, T_CIB_REPLACE_NOTIFY)) {
		is_replace = TRUE;
	}

	ipc_client = client->channel;
	qlen = ipc_client->send_queue->current_qlen;
	max_qlen = ipc_client->send_queue->max_qlen;

#if 1
	/* get_chan_status() causes memory to be allocated that isnt free'd
	 *   until the message is read (which messes up the memory stats) 
	 */
	if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) {
		crm_debug_2("Skipping notification to disconnected"
			    " client %s/%s", client->name, client->id);
		
	} else if(client->pre_notify && is_pre) {
		if(qlen < (int)(0.4 * max_qlen)) {
			do_send = TRUE;
		} else {
			crm_warn("Throttling pre-notifications due to"
				 " high load: queue=%d (max=%d)",
				 qlen, max_qlen);
		}
		 
	} else if(client->post_notify && is_post) {
		if(qlen < (int)(0.7 * max_qlen)) {
			do_send = TRUE;
		} else {
			crm_warn("Throttling post-notifications due to"
				 " extreme load: queue=%d (max=%d)",
				 qlen, max_qlen);
		}

		/* these are critical */
	} else
#endif
		if(client->diffs && is_diff) {
		do_send = TRUE;

	} else if(client->confirmations && is_confirm) {
		do_send = TRUE;

	} else if(client->replace && is_replace) {
		do_send = TRUE;
	}

	if(do_send) {
		crm_debug_2("Notifying client %s/%s of %s update (queue=%d)",
			    client->name, client->channel_name, type, qlen);

		if(ipc_client->send_queue->current_qlen >= ipc_client->send_queue->max_qlen) {
			/* We never want the CIB to exit because our client is slow */
			crm_crit("%s-notification of client %s/%s failed - queue saturated",
				 is_confirm?"Confirmation":is_post?"Post":"Pre",
				 client->name, client->id);
			
		} else if(send_ipc_message(ipc_client, update_msg) == FALSE) {
			crm_warn("Notification of client %s/%s failed",
				 client->name, client->id);
		}
		
	} else {
		crm_debug_3("Client %s/%s not interested in %s notifications",
			    client->name, client->channel_name, type);	
	}
}
Esempio n. 13
0
int 
stonithd_node_fence(stonith_ops_t * op)
{
	int rc = ST_FAIL;
	struct ha_msg *request, *reply;

	if (op == NULL) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: op==NULL");
		goto out;
	}
	
	if (!signed_on(chan)) {
		stdlib_log(LOG_NOTICE, "not signed on");
		goto out;
	}

	if (!(request = create_basic_reqmsg_fields(ST_STONITH))) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: "
			   "message creation failed.");
		goto out;
	}

	if (ha_msg_add_int(request, F_STONITHD_OPTYPE, op->optype) != HA_OK) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: "
			   "cannot add optype field to ha_msg.");
		goto out;
	}
	if (ha_msg_add(request, F_STONITHD_NODE, op->node_name ) != HA_OK) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: "
			   "cannot add node_name field to ha_msg.");
		goto out;
	}
	if (op->node_uuid == NULL || (ha_msg_add(request, F_STONITHD_NODE_UUID, 
					op->node_uuid) != HA_OK)) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: "
			   "cannot add node_uuid field to ha_msg.");
		goto out;
	}
	if (ha_msg_add_int(request, F_STONITHD_TIMEOUT, op->timeout) != HA_OK) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: "
			   "cannot add timeout field to ha_msg.");
		goto out;
	}
	if  (op->private_data == NULL || (ha_msg_add(request, F_STONITHD_PDATA, 
					op->private_data) != HA_OK)) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: "
		   "cannot add private_data field to ha_msg.");
		goto out;
	}

	/* Send the stonith request message */
	if (msg2ipcchan(request, chan) != HA_OK) {
		stdlib_log(LOG_ERR
			   , "failed to send stonith request to stonithd");
		goto out;
	}

	/*  waiting for the output to finish */
	chan_waitout_timeout(chan, DEFAULT_TIMEOUT);
	
	/* Read the reply... */
	stdlib_log(LOG_DEBUG, "waiting for the stonith reply msg.");
        if ( IPC_OK != chan_waitin_timeout(chan, DEFAULT_TIMEOUT) ) {
		stdlib_log(LOG_ERR, "%s:%d: waitin failed."
			   , __FUNCTION__, __LINE__);
		goto out;
	}

	if ( (reply = msgfromIPC_noauth(chan)) == NULL ) {
		stdlib_log(LOG_ERR, "stonithd_node_fence: fail to fetch reply");
		goto out;
	}
	
	if ( TRUE == is_expected_msg(reply, F_STONITHD_TYPE, ST_APIRPL, 
			     F_STONITHD_APIRPL, ST_RSTONITH, TRUE) ) {
		if( !STRNCMP_CONST(
			cl_get_string(reply,F_STONITHD_APIRET), ST_APIOK) ) {
			rc = ST_OK;
			stdlib_log(LOG_DEBUG, "%s:%d: %s"
				 , __FUNCTION__, __LINE__
				 , "stonithd's synchronous answer is ST_APIOK");
		} else {
			stdlib_log(LOG_ERR, "%s:%d: %s"
			       , __FUNCTION__, __LINE__
			       , "stonithd's synchronous answer is ST_APIFAIL");
		}
	} else {
		stdlib_log(LOG_ERR, "stonithd_node_fence: "
			   "Got an unexpected message.");
		/* Need to handle in other way? */
	}

out:
	ZAPMSG(reply);
	ZAPMSG(request);
	return rc;
}
Esempio n. 14
0
int
register_fsa_input_adv(
    enum crmd_fsa_cause cause, enum crmd_fsa_input input,
    void *data, long long with_actions,
    gboolean prepend, const char *raised_from)
{
    unsigned  old_len = g_list_length(fsa_message_queue);
    fsa_data_t *fsa_data = NULL;

    last_data_id++;
    CRM_CHECK(raised_from != NULL, raised_from = "<unknown>");

    crm_debug("%s %s FSA input %d (%s) (cause=%s) %s data",
              raised_from, prepend?"prepended":"appended",last_data_id, fsa_input2string(input),
              fsa_cause2string(cause), data?"with":"without");

    if(input == I_WAIT_FOR_EVENT) {
        do_fsa_stall = TRUE;
        crm_debug("Stalling the FSA pending further input: cause=%s",
                  fsa_cause2string(cause));
        if(old_len > 0) {
            crm_warn("%s stalled the FSA with pending inputs",
                     raised_from);
            fsa_dump_queue(LOG_DEBUG);
        }
        if(data == NULL) {
            set_bit_inplace(fsa_actions, with_actions);
            with_actions = A_NOTHING;
            return 0;
        }
        crm_err("%s stalled the FSA with data - this may be broken",
                raised_from);
    }

    if(old_len == 0) {
        last_was_vote = FALSE;
    }

    if(input == I_NULL && with_actions == A_NOTHING /* && data == NULL */) {
        /* no point doing anything */
        crm_err("Cannot add entry to queue: no input and no action");
        return 0;

    } else if(data == NULL) {
        last_was_vote = FALSE;

#if 0
    } else if(last_was_vote && cause == C_HA_MESSAGE && input == I_ROUTER) {
        const char *op = cl_get_string(
                             ((ha_msg_input_t*)data)->msg, F_CRM_TASK);
        if(safe_str_eq(op, CRM_OP_VOTE)) {
            /* It is always safe to treat N successive votes as
             *    a single one
             *
             * If all the discarded votes are more "loosing" than
             *    the first then the result is accurate
             *    (win or loose).
             *
             * If any of the discarded votes are less "loosing"
             *    than the first then we will cast our vote and the
             *    eventual winner will vote us down again (which
             *    even in the case that N=2, is no worse than if we
             *    had not disarded the vote).
             */
            crm_debug_2("Vote compression: %d", old_len);
            return 0;
        }
#endif
    } else if (cause == C_HA_MESSAGE && input == I_ROUTER) {
        const char *op = cl_get_string(
                             ((ha_msg_input_t*)data)->msg, F_CRM_TASK);
        if(safe_str_eq(op, CRM_OP_VOTE)) {
            last_was_vote = TRUE;
            crm_debug_3("Added vote: %d", old_len);
        }

    } else {
        last_was_vote = FALSE;
    }

    crm_malloc0(fsa_data, sizeof(fsa_data_t));
    fsa_data->id        = last_data_id;
    fsa_data->fsa_input = input;
    fsa_data->fsa_cause = cause;
    fsa_data->origin    = raised_from;
    fsa_data->data      = NULL;
    fsa_data->data_type = fsa_dt_none;
    fsa_data->actions   = with_actions;

    if(with_actions != A_NOTHING) {
        crm_debug_3("Adding actions %.16llx to input", with_actions);
    }

    if(data != NULL) {
        switch(cause) {
        case C_FSA_INTERNAL:
        case C_CRMD_STATUS_CALLBACK:
        case C_IPC_MESSAGE:
        case C_HA_MESSAGE:
            crm_debug_3("Copying %s data from %s as a HA msg",
                        fsa_cause2string(cause),
                        raised_from);
            fsa_data->data = copy_ha_msg_input(data);
            fsa_data->data_type = fsa_dt_ha_msg;
            break;

        case C_LRM_OP_CALLBACK:
            crm_debug_3("Copying %s data from %s as lrm_op_t",
                        fsa_cause2string(cause),
                        raised_from);
            fsa_data->data = copy_lrm_op((lrm_op_t*)data);
            fsa_data->data_type = fsa_dt_lrm;
            break;

        case C_CCM_CALLBACK:
            crm_debug_3("Copying %s data from %s as CCM data",
                        fsa_cause2string(cause),
                        raised_from);
            fsa_data->data = copy_ccm_data(data);
            fsa_data->data_type = fsa_dt_ccm;
            break;

        case C_SUBSYSTEM_CONNECT:
        case C_LRM_MONITOR_CALLBACK:
        case C_TIMER_POPPED:
        case C_SHUTDOWN:
        case C_HEARTBEAT_FAILED:
        case C_HA_DISCONNECT:
        case C_ILLEGAL:
        case C_UNKNOWN:
        case C_STARTUP:
            crm_err("Copying %s data (from %s)"
                    " not yet implemented",
                    fsa_cause2string(cause), raised_from);
            exit(1);
            break;
        }
        crm_debug_4("%s data copied",
                    fsa_cause2string(fsa_data->fsa_cause));
    }

    /* make sure to free it properly later */
    if(prepend) {
        crm_debug_2("Prepending input");
        fsa_message_queue = g_list_prepend(fsa_message_queue, fsa_data);
    } else {
        fsa_message_queue = g_list_append(fsa_message_queue, fsa_data);
    }

    crm_debug_2("Queue len: %d", g_list_length(fsa_message_queue));

    fsa_dump_queue(LOG_DEBUG_2);

    if(old_len == g_list_length(fsa_message_queue)) {
        crm_err("Couldnt add message to the queue");
    }

    if(fsa_source) {
        crm_debug_3("Triggering FSA: %s", __FUNCTION__);
        G_main_set_trigger(fsa_source);
    }
    return last_data_id;
}
Esempio n. 15
0
int
stonithd_receive_ops_result(gboolean blocking)
{
	struct ha_msg* reply = NULL;
	const char *reply_type;
	int rc = ST_OK;

	stdlib_log(LOG_DEBUG, "stonithd_receive_ops_result: begin");

	/* If there is no msg ready and none blocking mode, then return */
	if ((stonithd_op_result_ready() == FALSE) && (blocking == FALSE)) {
		stdlib_log(LOG_DEBUG, "stonithd_receive_ops_result: "
			   "no result available.");
		return ST_OK;
	}

	if (stonithd_op_result_ready() == FALSE) {
	/* at that time, blocking must be TRUE */
		rc = cbchan->ops->waitin(cbchan);
		if (IPC_OK != rc) {
			if (cbchan->ch_status == IPC_DISCONNECT) {
				stdlib_log(LOG_INFO, "%s:%d: disconnected",
				__FUNCTION__, __LINE__); 
			} else if (IPC_INTR == rc) {
				stdlib_log(LOG_INFO, "%s:%d: waitin interrupted",
				__FUNCTION__, __LINE__); 
			} else {
				stdlib_log(LOG_WARNING, "%s:%d: waitin failed: %d",
				__FUNCTION__, __LINE__,rc); 
			}
			return ST_FAIL;
		}
	}

	reply = msgfromIPC_noauth(cbchan);
	reply_type = cl_get_string(reply, F_STONITHD_APIRPL);
	if ( !is_expected_msg(reply, F_STONITHD_TYPE, ST_APIRPL, 
			     F_STONITHD_APIRPL, reply_type, TRUE)) {
		ZAPMSG(reply);
		stdlib_log(LOG_DEBUG, "%s:%d: "
			   "got an unexpected message", __FUNCTION__, __LINE__);
		return ST_FAIL;
	}
	if( !strcmp(reply_type, ST_STRET) ) {
		stonith_ops_t *st_op = NULL;
		/* handle the stonith op result message */
		if( !(st_op = g_new(stonith_ops_t, 1)) ) {
			stdlib_log(LOG_ERR, "out of memory");
			return ST_FAIL;
		}
		st_op->node_uuid = NULL;
		st_op->private_data = NULL;

		st_get_int_value(reply, F_STONITHD_OPTYPE, (int*)&st_op->optype);	
		st_save_string(reply, F_STONITHD_NODE, st_op->node_name);
		st_save_string(reply, F_STONITHD_NODE_UUID, st_op->node_uuid);
		st_get_int_value(reply, F_STONITHD_TIMEOUT, &st_op->timeout);
		st_get_int_value(reply, F_STONITHD_CALLID, &st_op->call_id);
		st_get_int_value(reply, F_STONITHD_FRC, (int*)&st_op->op_result);
		st_save_string(reply, F_STONITHD_NLIST, st_op->node_list);
		st_save_string(reply, F_STONITHD_PDATA, st_op->private_data);

		if (stonith_ops_cb != NULL) {
			stonith_ops_cb(st_op);
		}

		free_stonith_ops_t(st_op);
	}
	else if( !strcmp(reply_type, ST_RAOPRET) ) {
		stonithRA_ops_t *ra_op = NULL;
		/* handle the stonithRA op result message */
		if( !(ra_op = g_new(stonithRA_ops_t, 1)) ) {
			stdlib_log(LOG_ERR, "out of memory");
			return ST_FAIL;
		}

		st_save_string(reply, F_STONITHD_RSCID, ra_op->rsc_id);
		st_save_string(reply, F_STONITHD_RAOPTYPE, ra_op->op_type);
		st_save_string(reply, F_STONITHD_RANAME, ra_op->ra_name);
		st_get_hashtable(reply, F_STONITHD_PARAMS, ra_op->params);
		st_get_int_value(reply, F_STONITHD_CALLID, &ra_op->call_id);
		st_get_int_value(reply, F_STONITHD_FRC, &ra_op->op_result);

		/* if ( rc == ST_OK && stonithRA_ops_cb != NULL)  */
		if ( stonithRA_ops_cb ) {
			stonithRA_ops_cb(ra_op, stonithRA_ops_cb_private_data);
		}

		free_stonithRA_ops_t(ra_op);
	}
	else {
		stdlib_log(LOG_DEBUG, "%s:%d: "
			   "got an unexpected message", __FUNCTION__, __LINE__);
		rc = ST_FAIL;
	}
	ZAPMSG(reply);
	return rc;
}
Esempio n. 16
0
int
stonithd_virtual_stonithRA_ops( stonithRA_ops_t * op, int * call_id)
{
	int rc = ST_FAIL;
	struct ha_msg * request, * reply;
	const char * tmpstr;

	if (op == NULL) {
		stdlib_log(LOG_ERR, "stonithd_virtual_stonithRA_ops: op==NULL");
		return ST_FAIL;
	}
	
	if (call_id == NULL) {
		stdlib_log(LOG_ERR, "stonithd_stonithd_stonithRA_ops: "
			   "call_id==NULL");
		return ST_FAIL;
	}
	
	if ( !signed_on(chan) ) {
		stdlib_log(LOG_ERR, "not signed on");
		return ST_FAIL;
	}

	if ( (request = create_basic_reqmsg_fields(ST_RAOP)) == NULL) {
		return ST_FAIL;
	}

	if (  (ha_msg_add(request, F_STONITHD_RSCID, op->rsc_id) != HA_OK)
	    ||(ha_msg_add(request, F_STONITHD_RAOPTYPE, op->op_type) != HA_OK)
	    ||(ha_msg_add(request, F_STONITHD_RANAME, op->ra_name) != HA_OK)
	    ||(ha_msg_add_int(request, F_STONITHD_TIMEOUT, op->timeout) != HA_OK)
	    ||(ha_msg_addhash(request, F_STONITHD_PARAMS, op->params) != HA_OK)
	   ) {
		stdlib_log(LOG_ERR, "stonithd_virtual_stonithRA_ops: "
			   "cannot add field to ha_msg.");
		ZAPMSG(request);
		return ST_FAIL;
	}

	/* Send the request message */
	if (msg2ipcchan(request, chan) != HA_OK) {
		ZAPMSG(request);
		stdlib_log(LOG_ERR, "can't send stonithRA message to IPC");
		return ST_FAIL;
	}

	/*  waiting for the output to finish */
	chan_waitout_timeout(chan, DEFAULT_TIMEOUT);
	ZAPMSG(request);
	
	/* Read the reply... */
	stdlib_log(LOG_DEBUG, "waiting for the stonithRA reply msg.");
        if ( IPC_OK != chan_waitin_timeout(chan, DEFAULT_TIMEOUT) ) {
		stdlib_log(LOG_ERR, "%s:%d: waitin failed."
			   , __FUNCTION__, __LINE__);
		return ST_FAIL;
	}

	if ( (reply = msgfromIPC_noauth(chan)) == NULL ) {
		stdlib_log(LOG_ERR, "stonithd_virtual_stonithRA_ops: "
			   "failed to fetch reply");
		return ST_FAIL;
	}
	
	if ( FALSE == is_expected_msg(reply, F_STONITHD_TYPE, ST_APIRPL, 
			     F_STONITHD_APIRPL, ST_RRAOP, TRUE) ) {
		ZAPMSG(reply); /* avoid to zap the msg ? */
		stdlib_log(LOG_WARNING, "stonithd_virtual_stonithRA_ops: "
			   "got an unexpected message");
		return ST_FAIL;
	}

	if ( ((tmpstr = cl_get_string(reply, F_STONITHD_APIRET)) != NULL) 
	   	    && (STRNCMP_CONST(tmpstr, ST_APIOK) == 0) ) {
		int tmpint;

		if ( ha_msg_value_int(reply, F_STONITHD_CALLID, &tmpint)
			== HA_OK ) {
			*call_id = tmpint;
			rc = ST_OK;
			stdlib_log(LOG_DEBUG, "a stonith RA operation queue " \
				   "to run, call_id=%d.", *call_id);
		} else {
			stdlib_log(LOG_ERR, "no return call_id in reply");
			rc = ST_FAIL;
		}
	} else {
		stdlib_log(LOG_WARNING, "failed to do the RA op.");
		rc = ST_FAIL;
		* call_id = -1;		
	}

	ZAPMSG(reply);
	return rc;
}
Esempio n. 17
0
int stonithd_list_stonith_types(GList ** types)
{
	int rc = ST_FAIL;
	struct ha_msg * request, * reply;
	const char * tmpstr;

	if ( !signed_on(chan) ) {
		stdlib_log(LOG_ERR, "not signed on");
		return ST_FAIL;
	}

	if ( (request = create_basic_reqmsg_fields(ST_LTYPES)) == NULL) {
		return ST_FAIL;
	}

	/* Send the request message */
	if (msg2ipcchan(request, chan) != HA_OK) {
		ZAPMSG(request);
		stdlib_log(LOG_ERR, "can't send stonithRA message to IPC");
		return ST_FAIL;
	}

	/*  waiting for the output to finish */
	chan_waitout_timeout(chan, DEFAULT_TIMEOUT);
	ZAPMSG(request);
	
	/* Read the reply... */
	stdlib_log(LOG_DEBUG, "waiting for the reply to list stonith types.");
        if ( IPC_OK != chan_waitin_timeout(chan, DEFAULT_TIMEOUT) ) {
		stdlib_log(LOG_ERR, "%s:%d: chan_waitin failed."
			   , __FUNCTION__, __LINE__);
		return ST_FAIL;
	}

	if ( (reply = msgfromIPC_noauth(chan)) == NULL ) {
		stdlib_log(LOG_ERR, "stonithd_list_stonith_types: "
			   "failed to fetch reply.");
		return ST_FAIL;
	}
	
	*types = NULL;
	if ( TRUE == is_expected_msg(reply, F_STONITHD_TYPE, ST_APIRPL, 
			     F_STONITHD_APIRPL, ST_RLTYPES, TRUE) ) {
		if ( ((tmpstr = cl_get_string(reply, F_STONITHD_APIRET)) != NULL) 
	   	    && (STRNCMP_CONST(tmpstr, ST_APIOK) == 0) ) {
			int i;
			int len=cl_msg_list_length(reply, F_STONITHD_STTYPES);
			if ( len < 0 ) {
				stdlib_log(LOG_ERR, "Not field to list stonith "
					  "types.");
			} else {
				for (i = 0; i < len; i++) {
					tmpstr = cl_msg_list_nth_data(reply,
							F_STONITHD_STTYPES, i);
					if( tmpstr ) {
						*types = g_list_append(*types,
							       g_strdup(tmpstr));
					}
				}
				stdlib_log(LOG_DEBUG, "got stonith types.");
				rc = ST_OK;
			}
		} else {
			stdlib_log(LOG_DEBUG, "failed to get stonith types.");
		}
	} else {
		stdlib_log(LOG_DEBUG, "stonithd_list_stonith_types: "
			   "Got an unexpected message.");
	}

	ZAPMSG(reply);
	return rc;
}
Esempio n. 18
0
/*	 A_CIB_INVOKE, A_CIB_BUMPGEN, A_UPDATE_NODESTATUS	*/
void
do_cib_invoke(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)
{
	HA_Message *answer = NULL;
	ha_msg_input_t *cib_msg = fsa_typed_data(fsa_dt_ha_msg);
	const char *sys_from = cl_get_string(cib_msg->msg, F_CRM_SYS_FROM);

	if(fsa_cib_conn->state == cib_disconnected) {
		if(cur_state != S_STOPPING) {
			crm_err("CIB is disconnected");
			crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg);
			return;
		}
		crm_info("CIB is disconnected");
		crm_log_message_adv(LOG_DEBUG, "CIB Input", cib_msg->msg);
		return;
		
	}
	
	if(action & A_CIB_INVOKE) {
		if(safe_str_eq(sys_from, CRM_SYSTEM_CRMD)) {
			action = A_CIB_INVOKE_LOCAL;
		} else if(safe_str_eq(sys_from, CRM_SYSTEM_DC)) {
			action = A_CIB_INVOKE_LOCAL;
		}
	}
	

	if(action & A_CIB_INVOKE || action & A_CIB_INVOKE_LOCAL) {
		int call_options = 0;
		enum cib_errors rc  = cib_ok;
		crm_data_t *cib_frag  = NULL;
		
		const char *section  = NULL;
		const char *op   = cl_get_string(cib_msg->msg, F_CRM_TASK);

		section  = cl_get_string(cib_msg->msg, F_CIB_SECTION);
		
		ha_msg_value_int(cib_msg->msg, F_CIB_CALLOPTS, &call_options);

		crm_log_message(LOG_MSG, cib_msg->msg);
		crm_log_xml_debug_3(cib_msg->xml, "[CIB update]");
		if(op == NULL) {
			crm_err("Invalid CIB Message");
			register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
			return;
		}

		cib_frag = NULL;
		rc = fsa_cib_conn->cmds->variant_op(
			fsa_cib_conn, op, NULL, section,
			cib_msg->xml, &cib_frag, call_options);

		if(rc < cib_ok || (action & A_CIB_INVOKE)) {
			answer = create_reply(cib_msg->msg, cib_frag);
			ha_msg_add(answer,XML_ATTR_RESULT,cib_error2string(rc));
		}
		
		if(action & A_CIB_INVOKE) {
			if(relay_message(answer, TRUE) == FALSE) {
				crm_err("Confused what to do with cib result");
				crm_log_message(LOG_ERR, answer);
				crm_msg_del(answer);
				register_fsa_input(C_FSA_INTERNAL, I_ERROR, NULL);
				return;
			}

		} else if(rc < cib_ok) {
			ha_msg_input_t *input = NULL;
			crm_err("Internal CRM/CIB command from %s() failed: %s",
				msg_data->origin, cib_error2string(rc));
			crm_log_message_adv(LOG_WARNING, "CIB Input", cib_msg->msg);
			crm_log_message_adv(LOG_WARNING, "CIB Reply", answer);
			
			input = new_ha_msg_input(answer);
			register_fsa_input(C_FSA_INTERNAL, I_ERROR, input);
			crm_msg_del(answer);
			delete_ha_msg_input(input);
		}

	} else {
		crm_err("Unexpected action %s in %s",
			fsa_action2string(action), __FUNCTION__);
	}
}
Esempio n. 19
0
int
stonithd_signon(const char * client_name)
{
	int     rc = ST_FAIL;
	char	path[] = IPC_PATH_ATTR;
	char	sock[] = STONITHD_SOCK;
	char	cbsock[] = STONITHD_CALLBACK_SOCK;
	struct  ha_msg * request;
	struct  ha_msg * reply;
	GHashTable *	 wchanattrs;
	uid_t	my_euid;
	gid_t	my_egid;
	const char * tmpstr;
	int 	rc_tmp;
	gboolean connected = TRUE;
 	cl_uuid_t cookie, *cptr = NULL;

	if (chan == NULL || chan->ch_status != IPC_CONNECT) {
	    connected = FALSE;
	} else if (cbchan == NULL || cbchan->ch_status != IPC_CONNECT) {
	    connected = FALSE;
	}

	if(!connected) {
		/* cleanup */
		if (NULL != chan) {
		    chan->ops->destroy(chan);
		    chan = NULL;
		}
		if (NULL != cbchan) {
		    cbchan->ops->destroy(cbchan);
		    cbchan = NULL;
		}
		stdlib_log(LOG_DEBUG, "stonithd_signon: creating connection");
		wchanattrs = g_hash_table_new(g_str_hash, g_str_equal);
        	g_hash_table_insert(wchanattrs, path, sock);
		/* Connect to the stonith deamon */
		chan = ipc_channel_constructor(IPC_ANYTYPE, wchanattrs);
		g_hash_table_destroy(wchanattrs);
	
		if (chan == NULL) {
			stdlib_log(LOG_ERR, "stonithd_signon: Can't connect "
				   " to stonithd");
			rc = ST_FAIL;
			goto end;
		}

	        if (chan->ops->initiate_connection(chan) != IPC_OK) {
			stdlib_log(LOG_ERR, "stonithd_signon: Can't initiate "
				   "connection to stonithd");
			rc = ST_FAIL;
			goto end;
       		}
	}

	CLIENT_PID = getpid();
	snprintf(CLIENT_PID_STR, sizeof(CLIENT_PID_STR), "%d", CLIENT_PID);
	if ( client_name != NULL ) {
		CLIENT_NAME = client_name;
	} else {
		CLIENT_NAME = CLIENT_PID_STR;
	}

	if ( (request = create_basic_reqmsg_fields(ST_SIGNON)) == NULL) {
		rc = ST_FAIL;
		goto end;
	}

	/* important error check client name length */
	my_euid = geteuid();
	my_egid = getegid();
	if (  (	ha_msg_add_int(request, F_STONITHD_CEUID, my_euid) != HA_OK )
	    ||(	ha_msg_add_int(request, F_STONITHD_CEGID, my_egid) != HA_OK )
	    ||( ha_msg_add(request, F_STONITHD_COOKIE, "") != HA_OK )
	   ) {
		stdlib_log(LOG_ERR, "stonithd_signon: "
			   "cannot add field to ha_msg.");
		ZAPMSG(request);
		rc = ST_FAIL;
		goto end;
	}

	stdlib_log(LOG_DEBUG, "sending out the signon msg.");
	/* Send the registration request message */
	if (msg2ipcchan(request, chan) != HA_OK) {
		ZAPMSG(request);
		stdlib_log(LOG_ERR, "can't send signon message to IPC");
		rc = ST_FAIL;
		goto end;
	}

	/* waiting for the output to finish */
	do { 
		rc_tmp= chan_waitout_timeout(chan, DEFAULT_TIMEOUT);
	} while (rc_tmp == IPC_INTR);

	ZAPMSG(request);
	if (IPC_OK != rc_tmp) {
		stdlib_log(LOG_ERR, "%s:%d: waitout failed."
			   , __FUNCTION__, __LINE__);
		rc = ST_FAIL;
		goto end;
	}

	/* Read the reply... */
        if ( IPC_OK != chan_waitin_timeout(chan, DEFAULT_TIMEOUT) ) {
		stdlib_log(LOG_ERR, "%s:%d: waitin failed."
			   , __FUNCTION__, __LINE__);
		rc = ST_FAIL;
		goto end;
	}

	if ( (reply = msgfromIPC_noauth(chan)) == NULL ) {
		stdlib_log(LOG_ERR, "stonithd_signon: failed to fetch reply.");
		rc = ST_FAIL;
		goto end;
	}
	
	if ( TRUE == is_expected_msg(reply, F_STONITHD_TYPE, ST_APIRPL, 
			     F_STONITHD_APIRPL, ST_RSIGNON, TRUE) ) {
		if ( ((tmpstr=cl_get_string(reply, F_STONITHD_APIRET)) != NULL)
	   	    && (STRNCMP_CONST(tmpstr, ST_APIOK) == 0) ) {
			rc = ST_OK;
			stdlib_log(LOG_DEBUG, "signed on to stonithd.");
			/* get cookie if any */
			if( cl_get_uuid(reply, F_STONITHD_COOKIE, &cookie) == HA_OK ) {
				cptr = &cookie;
			}
		} else {
			stdlib_log(LOG_WARNING, "failed to signon to the "
				   "stonithd.");
		}
	} else {
		stdlib_log(LOG_ERR, "stonithd_signon: "
			   "Got an unexpected message.");
	}
	ZAPMSG(reply);

	if (ST_OK != rc) { /* Something wrong when try to sign on to stonithd */
		goto end;
	}

	/* Connect to the stonith deamon via callback channel */
	wchanattrs = g_hash_table_new(g_str_hash, g_str_equal);
        g_hash_table_insert(wchanattrs, path, cbsock);
	cbchan = ipc_channel_constructor(IPC_ANYTYPE, wchanattrs);
	g_hash_table_destroy(wchanattrs);

	if (cbchan == NULL) {
		stdlib_log(LOG_ERR, "stonithd_signon: Can't construct "
			   "callback channel to stonithd.");
		rc = ST_FAIL;
		goto end;
	}

        if (cbchan->ops->initiate_connection(cbchan) != IPC_OK) {
		stdlib_log(LOG_ERR, "stonithd_signon: Can't initiate "
			   "connection with the callback channel");
		rc = ST_FAIL;
		goto end;
 	}

	if ( (reply = msgfromIPC_noauth(cbchan)) == NULL ) {
		stdlib_log(LOG_ERR, "%s:%d: failed to fetch reply via the "
			   " callback channel"
			   , __FUNCTION__, __LINE__);
		rc = ST_FAIL;
		goto end;
	}
	
	if ( TRUE == is_expected_msg(reply, F_STONITHD_TYPE, ST_APIRPL, 
			     F_STONITHD_APIRPL, ST_RSIGNON, TRUE) ) {
		tmpstr=cl_get_string(reply, F_STONITHD_APIRET);
		if ( !STRNCMP_CONST(tmpstr, ST_APIOK) ) {
			/* 
			 * If the server directly authenticates us (probably 
			 * via pid-auth), go ahead.
			 */
			stdlib_log(LOG_DEBUG, "%s:%d: Got a good signon reply "
				  "via the callback channel."
				   , __FUNCTION__, __LINE__);
		} else if ( !STRNCMP_CONST(tmpstr, ST_COOKIE) ) {
			/*
			 * If the server asks for a cookie to identify myself,
			 * initiate cookie authentication.
			 */
			if (cptr == NULL) {
				stdlib_log(LOG_ERR, "server requested cookie auth on "
					"the callback channel, but it didn't "
					"provide the cookie on the main channel.");
				rc = ST_FAIL;
			} else {
				rc = authenticate_with_cookie(cbchan, cptr);
			}
		} else {
			/* Unknown response. */
			rc = ST_FAIL;
			stdlib_log(LOG_ERR, "%s:%d: Got a bad signon reply "
				  "via the callback channel."
				   , __FUNCTION__, __LINE__);
		}
	} else {
		rc = ST_FAIL;
		stdlib_log(LOG_ERR, "stonithd_signon: "
			   "Got an unexpected message via the callback chan.");
	}
	ZAPMSG(reply);

end:
	if (ST_OK != rc) {
		/* Something wrong when confirm via callback channel */
		stonithd_signoff();
	}

	return rc;
}
Esempio n. 20
0
int
struct_display_as_xml(
	int log_level, int depth, struct ha_msg *data,
	const char *prefix, gboolean formatted) 
{
	int lpc = 0;
	int printed = 0;
	gboolean has_children = FALSE;
	char print_buffer[1000];
	char *buffer = print_buffer;
	const char *name = cl_get_string(data, F_XML_TAGNAME);

	if(data == NULL) {
		return 0;

	} else if(name == NULL) {
		cl_log(LOG_WARNING, "Struct at depth %d had no name", depth);
		cl_log_message(log_level, data);
		return 0;
	}
	
	if(formatted) {
		printed = struct_display_print_spaces(buffer, depth);
		update_buffer_head(buffer, printed);
	}
	
	printed = sprintf(buffer, "<%s", name);
	update_buffer_head(buffer, printed);
	
	for (lpc = 0; lpc < data->nfields; lpc++) {
		const char *prop_name = data->names[lpc];
		const char *prop_value = data->values[lpc];
		if(data->types[lpc] != FT_STRING) {
			continue;
		} else if(prop_name == NULL) {
			continue;
		} else if(prop_name[0] == '_' && prop_name[1] == '_') {
			continue;
		}
		printed = sprintf(buffer, " %s=\"%s\"", prop_name, prop_value);
		update_buffer_head(buffer, printed);
	}

	for (lpc = 0; lpc < data->nfields; lpc++) {
		if(data->types[lpc] == FT_STRUCT) {
			has_children = TRUE;
			break;
		}
	}

	printed = sprintf(buffer, "%s>", has_children==0?"/":"");
	update_buffer_head(buffer, printed);
	cl_log(log_level, "%s%s", prefix?prefix:"", print_buffer);
	buffer = print_buffer;
	
	if(has_children == FALSE) {
		return 0;
	}
	
	for (lpc = 0; lpc < data->nfields; lpc++) {
		if(data->types[lpc] != FT_STRUCT) {
			continue;
		} else if(0 > struct_display_as_xml(
				  log_level, depth+1, data->values[lpc],
				  prefix, formatted)) {
			return -1;
		}
	}

	if(formatted) {
		printed = struct_display_print_spaces(buffer, depth);
		update_buffer_head(buffer, printed);
	}
	cl_log(log_level, "%s%s</%s>", prefix?prefix:"", print_buffer, name);

	return 0;
}