Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/cib/callbacks.c b/crm/cib/callbacks.c
index 745770b130..0e5572ece2 100644
--- a/crm/cib/callbacks.c
+++ b/crm/cib/callbacks.c
@@ -1,1393 +1,1393 @@
-/* $Id: callbacks.c,v 1.71 2005/06/28 08:11:07 andrew Exp $ */
+/* $Id: callbacks.c,v 1.72 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/uids.h>
#include <clplumbing/cl_uuid.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/ipc.h>
#include <crm/common/ctrl.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <cibio.h>
#include <callbacks.h>
#include <cibmessages.h>
#include <notify.h>
#include <crm/dmalloc_wrapper.h>
gint cib_GCompareFunc(gconstpointer a, gconstpointer b);
gboolean cib_msg_timeout(gpointer data);
void cib_GHFunc(gpointer key, gpointer value, gpointer user_data);
gboolean ghash_str_clfree(gpointer key, gpointer value, gpointer user_data);
gboolean can_write(int flags);
HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data);
gboolean ccm_manual_check(gpointer data);
extern enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
void send_cib_replace(const HA_Message *sync_request, const char *host);
void cib_process_request(const HA_Message *request, gboolean privileged,
gboolean from_peer, cib_client_t *cib_client);
gboolean syncd_once = FALSE;
GHashTable *peer_hash = NULL;
int next_client_id = 0;
gboolean cib_is_master = FALSE;
gboolean cib_have_quorum = FALSE;
char * ccm_transition_id = NULL;
GHashTable *client_list = NULL;
GHashTable *ccm_membership = NULL;
extern const char *cib_our_uname;
extern ll_cluster_t *hb_conn;
extern int set_connected_peers(crm_data_t *xml_obj);
/*
typedef struct cib_operation_s
{
const char* operation;
gboolean modifies_cib;
gboolean needs_privileges;
gboolean needs_quorum;
gboolean needs_section;
gboolean needs_data;
enum cib_errors (*fn)(
const char *, int, const char *,
crm_data_t*, crm_data_t*, crm_data_t**, crm_data_t**);
} cib_operation_t;
*/
/* technically bump does modify the cib...
* but we want to split the "bump" from the "sync"
*/
cib_operation_t cib_server_ops[] = {
{NULL, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default},
{CRM_OP_NOOP, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_default},
{CIB_OP_APPLY_DIFF,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_diff},
{CIB_OP_SLAVE, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_SLAVEALL, TRUE, TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_SYNC_ONE, FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync_one},
{CIB_OP_MASTER, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_ISMASTER, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_readwrite},
{CIB_OP_BUMP, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_bump},
{CIB_OP_REPLACE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_replace},
{CIB_OP_CREATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CIB_OP_UPDATE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CIB_OP_DELETE, TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_delete},
{CIB_OP_DELETE_ALT,TRUE, TRUE, TRUE, TRUE, TRUE, cib_process_modify},
{CIB_OP_QUERY, FALSE,FALSE,FALSE,TRUE, FALSE,cib_process_query},
{CIB_OP_SYNC, FALSE,TRUE, FALSE,TRUE, FALSE,cib_process_sync},
{CRM_OP_QUIT, FALSE,TRUE, FALSE,FALSE,FALSE,cib_process_quit},
{CRM_OP_PING, FALSE,FALSE,FALSE,FALSE,FALSE,cib_process_ping},
{CIB_OP_ERASE, TRUE, TRUE, TRUE, TRUE, FALSE,cib_process_erase}
};
int send_via_callback_channel(HA_Message *msg, const char *token);
enum cib_errors cib_process_command(
const HA_Message *request, HA_Message **reply,
crm_data_t **cib_diff, gboolean privileged);
gboolean cib_common_callback(
IPC_Channel *channel, gpointer user_data, gboolean privileged);
enum cib_errors cib_get_operation_id(const HA_Message * msg, int *operation);
gboolean cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client);
gboolean
cib_client_connect(IPC_Channel *channel, gpointer user_data)
{
gboolean auth_failed = FALSE;
gboolean can_connect = TRUE;
gboolean (*client_callback)(IPC_Channel *channel, gpointer user_data) = NULL;
cib_client_t *new_client = NULL;
crm_debug_3("Connecting channel");
if (channel == NULL) {
crm_err("Channel was NULL");
can_connect = FALSE;
} else if (channel->ch_status == IPC_DISCONNECT) {
crm_err("Channel was disconnected");
can_connect = FALSE;
} else if(user_data == NULL) {
crm_err("user_data must contain channel name");
can_connect = FALSE;
} else {
crm_malloc0(new_client, sizeof(cib_client_t));
new_client->id = NULL;
new_client->callback_id = NULL;
new_client->source = NULL;
new_client->channel = channel;
new_client->channel_name = user_data;
new_client->delegated_calls = NULL;
crm_debug_3("Created channel %p for channel %s",
new_client, new_client->channel_name);
client_callback = NULL;
/* choose callback and do auth based on channel_name */
if(safe_str_eq(new_client->channel_name, cib_channel_callback)) {
client_callback = cib_null_callback;
} else {
cl_uuid_t client_id;
cl_uuid_generate(&client_id);
crm_malloc0(new_client->id, sizeof(char)*36);
cl_uuid_unparse(&client_id, new_client->id);
new_client->id[35] = EOS;
cl_uuid_generate(&client_id);
crm_malloc0(new_client->callback_id, sizeof(char)*36);
cl_uuid_unparse(&client_id, new_client->callback_id);
new_client->callback_id[35] = EOS;
client_callback = cib_ro_callback;
if(safe_str_eq(new_client->channel_name, cib_channel_rw)) {
client_callback = cib_rw_callback;
}
}
}
if(auth_failed) {
crm_err("Connection to %s channel failed authentication",
(char *)user_data);
can_connect = FALSE;
}
if(can_connect == FALSE) {
if(new_client) {
crm_free(new_client->id);
crm_free(new_client->callback_id);
}
crm_free(new_client);
return FALSE;
}
channel->ops->set_recv_qlen(channel, 100);
if(safe_str_eq(new_client->channel_name, cib_channel_callback)) {
channel->ops->set_send_qlen(channel, 400);
} else {
channel->ops->set_send_qlen(channel, 100);
}
if(client_callback != NULL) {
new_client->source = G_main_add_IPC_Channel(
G_PRIORITY_LOW, channel, FALSE, client_callback,
new_client, default_ipc_connection_destroy);
}
if(client_callback != cib_null_callback) {
/* send msg to client with uuid to use when signing up for
* callback channel
*/
HA_Message *reg_msg = ha_msg_new(3);
ha_msg_add(reg_msg, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(reg_msg, F_CIB_CLIENTID, new_client->id);
ha_msg_add(
reg_msg, F_CIB_CALLBACK_TOKEN, new_client->callback_id);
send_ipc_message(channel, reg_msg);
/* make sure we can find ourselves later for sync calls
* redirected to the master instance
*/
g_hash_table_insert(client_list, new_client->id, new_client);
}
crm_debug_3("Channel %s connected for client %s",
new_client->channel_name, new_client->id);
return TRUE;
}
gboolean
cib_rw_callback(IPC_Channel *channel, gpointer user_data)
{
return cib_common_callback(channel, user_data, TRUE);
}
gboolean
cib_ro_callback(IPC_Channel *channel, gpointer user_data)
{
return cib_common_callback(channel, user_data, FALSE);
}
gboolean
cib_null_callback(IPC_Channel *channel, gpointer user_data)
{
gboolean did_disconnect = TRUE;
HA_Message *op_request = NULL;
cib_client_t *cib_client = user_data;
cib_client_t *hash_client = NULL;
const char *type = NULL;
const char *uuid_ticket = NULL;
const char *client_name = NULL;
gboolean register_failed = FALSE;
if(cib_client == NULL) {
crm_err("Discarding IPC message from unknown source"
" on callback channel.");
return FALSE;
}
while(channel->ops->is_message_pending(channel)) {
if (channel->ch_status != IPC_CONNECT) {
/* The message which was pending for us is that
* the channel is no longer fully connected.
*
* Dont read requests from disconnected clients
*/
break;
}
op_request = msgfromIPC_noauth(channel);
type = cl_get_string(op_request, F_CIB_OPERATION);
if(safe_str_eq(type, T_CIB_NOTIFY) ) {
/* Update the notify filters for this client */
int on_off = 0;
ha_msg_value_int(
op_request, F_CIB_NOTIFY_ACTIVATE, &on_off);
type = cl_get_string(op_request, F_CIB_NOTIFY_TYPE);
if(safe_str_eq(type, T_CIB_POST_NOTIFY)) {
cib_client->post_notify = on_off;
} else if(safe_str_eq(type, T_CIB_PRE_NOTIFY)) {
cib_client->pre_notify = on_off;
} else if(safe_str_eq(type, T_CIB_UPDATE_CONFIRM)) {
cib_client->confirmations = on_off;
} else if(safe_str_eq(type, T_CIB_DIFF_NOTIFY)) {
cib_client->diffs = on_off;
}
continue;
} else if(safe_str_neq(type, CRM_OP_REGISTER) ) {
crm_warn("Discarding IPC message from %s on callback channel",
cib_client->id);
crm_msg_del(op_request);
continue;
}
uuid_ticket = cl_get_string(op_request, F_CIB_CALLBACK_TOKEN);
client_name = cl_get_string(op_request, F_CIB_CLIENTNAME);
CRM_DEV_ASSERT(uuid_ticket != NULL);
if(crm_assert_failed) {
register_failed = crm_assert_failed;
}
CRM_DEV_ASSERT(client_name != NULL);
if(crm_assert_failed) {
register_failed = crm_assert_failed;
}
if(register_failed == FALSE) {
hash_client = g_hash_table_lookup(client_list, uuid_ticket);
if(hash_client != NULL) {
crm_err("Duplicate registration request..."
" disconnecting");
register_failed = TRUE;
}
}
if(register_failed) {
crm_err("Registration request failed... disconnecting");
crm_msg_del(op_request);
return FALSE;
}
cib_client->id = crm_strdup(uuid_ticket);
cib_client->name = crm_strdup(client_name);
g_hash_table_insert(client_list, cib_client->id, cib_client);
crm_debug_2("Registered %s on %s channel",
cib_client->id, cib_client->channel_name);
crm_msg_del(op_request);
op_request = ha_msg_new(2);
ha_msg_add(op_request, F_CIB_OPERATION, CRM_OP_REGISTER);
ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id);
send_ipc_message(channel, op_request);
}
did_disconnect = cib_process_disconnect(channel, cib_client);
if(did_disconnect) {
crm_debug_2("Client disconnected");
}
return did_disconnect;
}
gboolean
cib_common_callback(
IPC_Channel *channel, gpointer user_data, gboolean privileged)
{
int rc = cib_ok;
int lpc = 0;
HA_Message *op_request = NULL;
cib_client_t *cib_client = user_data;
if(cib_client == NULL) {
crm_err("Receieved call from unknown source. Discarding.");
return FALSE;
}
crm_debug_2("Callback for %s on %s channel",
cib_client->id, cib_client->channel_name);
while(channel->ops->is_message_pending(channel)) {
if (channel->ch_status != IPC_CONNECT) {
/* The message which was pending for us is that
* the channel is no longer fully connected.
*
* Dont read requests from disconnected clients
*/
break;
}
op_request = msgfromIPC(channel, 0);
if (op_request == NULL) {
perror("Receive failure:");
break;
}
crm_debug_2("Processing IPC message from %s on %s channel",
cib_client->id, cib_client->channel_name);
crm_log_message_adv(LOG_MSG, "Client[inbound]", op_request);
lpc++;
rc = cib_ok;
CRM_DEV_ASSERT(
ha_msg_add(op_request, F_CIB_CLIENTID, cib_client->id) == HA_OK);
if(crm_assert_failed == FALSE) {
cib_process_request(
op_request, privileged, FALSE, cib_client);
}
crm_debug_3("Cleaning up request");
crm_msg_del(op_request);
op_request = NULL;
}
crm_debug_2("Processed %d messages", lpc);
return cib_process_disconnect(channel, cib_client);
}
void
cib_process_request(const HA_Message *request, gboolean privileged,
gboolean from_peer, cib_client_t *cib_client)
{
int call_type = 0;
int call_options = 0;
gboolean process = TRUE;
gboolean needs_reply = TRUE;
gboolean local_notify = FALSE;
gboolean needs_forward = FALSE;
crm_data_t *result_diff = NULL;
enum cib_errors rc = cib_ok;
HA_Message *op_reply = NULL;
const char *op = cl_get_string(request, F_CIB_OPERATION);
const char *originator = cl_get_string(request, F_ORIG);
const char *host = cl_get_string(request, F_CIB_HOST);
const char *reply_to = cl_get_string(request, F_CIB_ISREPLY);
const char *update = cl_get_string(request, F_CIB_GLOBAL_UPDATE);
const char *delegated = cl_get_string(request, F_CIB_DELEGATED);
const char *client_id = NULL;
crm_debug_4("%s Processing msg %s",
cib_our_uname, cl_get_string(request, F_SEQ));
if(host != NULL && strlen(host) == 0) {
host = NULL;
}
ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
crm_debug_4("Retrieved call options: %d", call_options);
crm_debug_2("Processing %s message (%s) to %s...",
from_peer?"peer":"local",originator, host?host:"master");
rc = cib_get_operation_id(request, &call_type);
if(rc != cib_ok) {
/* TODO: construct error reply */
crm_err("Pre-processing of command failed: %s",
cib_error2string(rc));
} else if(from_peer == FALSE) {
needs_reply = FALSE;
if(host == NULL && (call_options & cib_scope_local)) {
crm_debug("Processing locally scoped %s op from %s",
op, cib_client->name);
local_notify = TRUE;
} else if(host == NULL && cib_is_master) {
crm_debug("Processing master %s op locally from %s",
op, cib_client->name);
local_notify = TRUE;
} else if(safe_str_eq(host, cib_our_uname)) {
crm_debug("Processing locally addressed %s op from %s",
op, cib_client->name);
local_notify = TRUE;
} else {
crm_debug("%s op from %s needs to be forwarded to %s",
op, cib_client->name,
host?host:"the master instance");
needs_forward = TRUE;
process = FALSE;
}
} else if(crm_is_true(update) && safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Processing global/peer update from %s"
" that originated from us", originator);
needs_reply = FALSE;
local_notify = TRUE;
} else if(crm_is_true(update)) {
crm_debug("Processing global/peer update from %s", originator);
needs_reply = FALSE;
} else if(host != NULL && safe_str_eq(host, cib_our_uname)) {
crm_debug("Processing request sent to us from %s", originator);
} else if(delegated != NULL && cib_is_master == TRUE) {
crm_debug("Processing request sent to master instance from %s",
originator);
} else if(reply_to != NULL && safe_str_eq(reply_to, cib_our_uname)) {
crm_debug("Forward reply sent from %s to local clients",
originator);
process = FALSE;
needs_reply = FALSE;
local_notify = TRUE;
} else if(delegated != NULL) {
crm_debug_2("Ignoring msg for master instance");
return;
} else if(host != NULL) {
/* this is for a specific instance and we're not it */
crm_debug_2("Ignoring msg for instance on %s", crm_str(host));
return;
} else if(reply_to == NULL && cib_is_master == FALSE) {
/* this is for the master instance and we're not it */
crm_debug_2("Ignoring reply to %s", crm_str(reply_to));
return;
} else {
crm_err("Nothing for us to do?");
crm_log_message_adv(LOG_ERR, "Peer[inbound]", request);
return;
}
crm_debug_3("Finished determining processing actions");
if(call_options & cib_discard_reply) {
needs_reply = cib_server_ops[call_type].modifies_cib;
local_notify = FALSE;
}
if(needs_forward) {
HA_Message *forward_msg = cib_msg_copy(request, TRUE);
ha_msg_add(forward_msg, F_CIB_DELEGATED, cib_our_uname);
crm_log_message(LOG_MSG, forward_msg);
if(host != NULL) {
crm_debug("Forwarding %s op to %s", op, host);
send_ha_message(hb_conn, forward_msg, host);
} else {
crm_debug("Forwarding %s op to master instance", op);
send_ha_message(hb_conn, forward_msg, NULL);
}
if(call_options & cib_discard_reply) {
crm_debug_2("Client not interested in reply");
crm_msg_del(forward_msg);
} else if(call_options & cib_sync_call) {
/* keep track of the request so we can time it
* out if required
*/
crm_debug("Registering delegated call from %s",
cib_client->id);
cib_client->delegated_calls = g_list_append(
cib_client->delegated_calls, forward_msg);
} else {
crm_msg_del(forward_msg);
}
return;
}
if(process) {
crm_debug_3("Performing local processing:"
" op=%s origin=%s/%s,%s (update=%s)",
cl_get_string(request, F_CIB_OPERATION), originator,
cl_get_string(request, F_CIB_CLIENTID),
cl_get_string(request, F_CIB_CALLID), update);
rc = cib_process_command(request, &op_reply, &result_diff, TRUE);
crm_debug_3("Processing complete");
if(rc == cib_diff_resync || rc == cib_diff_failed
|| rc == cib_old_data) {
crm_warn("%s operation failed: %s",
crm_str(op), cib_error2string(rc));
} else if(rc != cib_ok) {
crm_err("%s operation failed: %s",
crm_str(op), cib_error2string(rc));
crm_log_message_adv(LOG_DEBUG, "CIB[output]", op_reply);
crm_debug("Input message");
crm_log_message(LOG_DEBUG, request);
}
if(op_reply == NULL && (needs_reply || local_notify)) {
crm_err("Unexpected NULL reply to message");
crm_log_message(LOG_ERR, request);
needs_reply = FALSE;
local_notify = FALSE;
}
}
crm_debug_3("processing response cases");
if(local_notify) {
/* send callback to originating child */
cib_client_t *client_obj = NULL;
HA_Message *client_reply = NULL;
enum cib_errors local_rc = cib_ok;
crm_debug_4("find the client");
if(process == FALSE) {
client_reply = cib_msg_copy(request, TRUE);
} else {
client_reply = cib_msg_copy(op_reply, TRUE);
}
client_id = cl_get_string(request, F_CIB_CLIENTID);
if(client_id != NULL) {
client_obj = g_hash_table_lookup(
client_list, client_id);
} else {
crm_debug("No client to sent the response to."
" F_CIB_CLIENTID not set.");
}
crm_debug_3("Sending callback to request originator");
if(client_obj != NULL) {
crm_debug_2("Sending %ssync response to %s %s",
(call_options & cib_sync_call)?"":"an a-",
client_obj->id,
from_peer?"(originator of delegated request)":"");
if(call_options & cib_sync_call) {
send_via_callback_channel(
client_reply, client_obj->id);
} else {
send_via_callback_channel(
client_reply, client_obj->callback_id);
}
} else {
crm_warn("Client %s may have left us",
crm_str(client_id));
crm_msg_del(client_reply);
}
if(local_rc != cib_ok) {
crm_warn("%sSync reply failed: %s",
(call_options & cib_sync_call)?"":"A-",
cib_error2string(local_rc));
crm_log_message(LOG_DEBUG, op_reply);
}
}
if(needs_reply == FALSE) {
/* nothing more to do...
* this was a non-originating slave update
*/
crm_debug_3("Completed slave update");
crm_msg_del(op_reply);
free_xml(result_diff);
return;
}
crm_debug_4("add the originator to message");
CRM_DEV_ASSERT(op_reply != NULL);
CRM_DEV_ASSERT(cib_server_ops[call_type].modifies_cib == FALSE
|| result_diff != NULL || rc != cib_ok);
/* from now on we are the server */
if(rc == cib_ok
&& result_diff != NULL
&& cib_server_ops[call_type].modifies_cib
&& !(call_options & cib_inhibit_bcast)) {
/* this (successful) call modified the CIB _and_ the
* change needs to be broadcast...
* send via HA to other nodes
*/
HA_Message *op_bcast = cib_msg_copy(request, FALSE);
crm_debug_2("Sending update diff to everyone");
ha_msg_add(op_bcast, F_CIB_ISREPLY, originator);
ha_msg_add(op_bcast, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
ha_msg_mod(op_bcast, F_CIB_OPERATION, CIB_OP_APPLY_DIFF);
add_message_xml(op_bcast, F_CIB_UPDATE_DIFF, result_diff);
crm_log_message(LOG_DEBUG_3, op_bcast);
send_ha_message(hb_conn, op_bcast, NULL);
crm_msg_del(op_bcast);
} else if((call_options & cib_discard_reply) == 0) {
if(from_peer && originator != NULL) {
/* send reply via HA to originating node */
crm_debug("Sending request result to originator only");
ha_msg_add(op_reply, F_CIB_ISREPLY, originator);
send_ha_message(hb_conn, op_reply, originator);
}
if(call_options & cib_inhibit_bcast ) {
crm_debug("Request not broadcast: inhibited");
}
if(cib_server_ops[call_type].modifies_cib == FALSE) {
crm_debug_2("Request not broadcast: R/O call");
}
if(rc != cib_ok) {
crm_warn("Request not broadcast: call failed: %s",
cib_error2string(rc));
}
}
crm_msg_del(op_reply);
free_xml(result_diff);
return;
}
enum cib_errors
cib_process_command(const HA_Message *request, HA_Message **reply,
crm_data_t **cib_diff, gboolean privileged)
{
crm_data_t *output = NULL;
crm_data_t *input = NULL;
crm_data_t *input_fragment = NULL;
crm_data_t *current_cib = the_cib;
crm_data_t *result_cib = NULL;
crm_data_t *local_diff = NULL;
int call_type = 0;
int call_options = 0;
enum cib_errors rc = cib_ok;
const char *op = NULL;
const char *call_id = NULL;
const char *section = NULL;
const char *tmp = NULL;
gboolean global_update = crm_is_true(
cl_get_string(request, F_CIB_GLOBAL_UPDATE));
CRM_DEV_ASSERT(reply != NULL);
if(reply) { *reply = NULL; }
/* Start processing the request... */
op = cl_get_string(request, F_CIB_OPERATION);
call_id = cl_get_string(request, F_CIB_CALLID);
ha_msg_value_int(request, F_CIB_CALLOPTS, &call_options);
crm_debug_4("Processing call id: %s", call_id);
rc = cib_get_operation_id(request, &call_type);
if(rc == cib_ok &&
cib_server_ops[call_type].needs_privileges
&& privileged == FALSE) {
/* abort */
rc = cib_not_authorized;
}
if(rc == cib_ok
&& global_update == FALSE
&& cib_server_ops[call_type].needs_quorum
&& can_write(call_options) == FALSE) {
rc = cib_no_quorum;
}
/* prevent NUMUPDATES from being incrimented - apply the change as-is */
if(global_update) {
call_options |= cib_inhibit_bcast;
}
if(rc == cib_ok && cib_server_ops[call_type].needs_section) {
section = cl_get_string(request, F_CIB_SECTION);
}
if(rc == cib_ok && safe_str_eq(op, CIB_OP_APPLY_DIFF)) {
crm_debug_4("Unpacking diff data in %s", F_CIB_UPDATE_DIFF);
input_fragment = get_message_xml(request, F_CIB_UPDATE_DIFF);
if(global_update) {
call_options |= cib_force_diff;
}
} else if(rc == cib_ok && safe_str_eq(op, CIB_OP_SYNC)) {
input_fragment = ha_msg_copy(request);
} else if(rc == cib_ok && safe_str_eq(op, CIB_OP_SYNC_ONE)) {
input_fragment = ha_msg_copy(request);
} else if(rc == cib_ok && cib_server_ops[call_type].needs_data) {
crm_debug_4("Unpacking data in %s", F_CIB_CALLDATA);
input_fragment = get_message_xml(request, F_CIB_CALLDATA);
}
/* extract the CIB from the fragment */
if(input_fragment != NULL
&& safe_str_eq(crm_element_name(input_fragment), XML_TAG_FRAGMENT)) {
input = find_xml_node(input_fragment, XML_TAG_CIB, TRUE);
} else {
input = input_fragment;
}
/* grab the section specified for the command */
if(input != NULL && safe_str_eq(crm_element_name(input), XML_TAG_CIB)){
rc = revision_check(input, current_cib, call_options);
if(rc == cib_ok) {
input = get_object_root(section, input);
}
}
if(cib_server_ops[call_type].modifies_cib) {
cib_pre_notify(
call_options, op,
get_object_root(section, current_cib), input);
}
if(rc == cib_ok) {
rc = cib_server_ops[call_type].fn(
op, call_options, section, input,
current_cib, &result_cib, &output);
}
if(cib_server_ops[call_type].modifies_cib) {
if(safe_str_eq(op, CIB_OP_APPLY_DIFF)) {
local_diff = copy_xml(input);
} else if(result_cib != NULL && current_cib != result_cib) {
local_diff = diff_cib_object(
current_cib, result_cib, FALSE);
}
if(rc != cib_ok) {
free_xml(result_cib);
} else if(activateCibXml(result_cib,CIB_FILENAME) < 0){
crm_warn("Activation failed");
rc = cib_ACTIVATION;
}
cib_post_notify(call_options, op, input, rc, the_cib);
cib_diff_notify(call_options, op, input, rc, local_diff);
} else if(result_cib != NULL) {
crm_err("%s call modified the CIB", op);
free_xml(result_cib);
}
crm_debug_4("Processing reply cases");
if((call_options & cib_discard_reply)
&& cib_server_ops[call_type].modifies_cib == FALSE) {
crm_debug_3("No reply needed for call %s", call_id);
return rc;
} else if(reply == NULL) {
crm_debug("No reply possible for call %s", call_id);
return rc;
}
crm_debug_4("Creating a basic reply");
*reply = ha_msg_new(8);
ha_msg_add(*reply, F_TYPE, T_CIB);
ha_msg_add(*reply, F_CIB_OPERATION, op);
ha_msg_add(*reply, F_CIB_CALLID, call_id);
ha_msg_add_int(*reply, F_CIB_RC, rc);
tmp = cl_get_string(request, F_CIB_CLIENTID);
ha_msg_add(*reply, F_CIB_CLIENTID, tmp);
tmp = cl_get_string(request, F_CIB_CALLOPTS);
ha_msg_add(*reply, F_CIB_CALLOPTS, tmp);
crm_debug_4("Attaching output if necessary");
if(output != NULL) {
add_message_xml(*reply, F_CIB_CALLDATA, output);
} else {
crm_debug_3("No output for call %s", call_id);
}
crm_debug_4("Cleaning up");
if(cib_diff != NULL) {
*cib_diff = local_diff;
} else {
free_xml(local_diff);
}
free_xml(output);
free_xml(input_fragment);
return rc;
}
int
send_via_callback_channel(HA_Message *msg, const char *token)
{
cib_client_t *hash_client = NULL;
GList *list_item = NULL;
enum cib_errors rc = cib_ok;
crm_debug_3("Delivering msg %p to client %s", msg, token);
if(token == NULL) {
crm_err("No client id token, cant send message");
if(rc == cib_ok) {
rc = cib_missing;
}
} else {
/* A client that left before we could reply is not really
* _our_ error. Warn instead.
*/
hash_client = g_hash_table_lookup(client_list, token);
if(hash_client == NULL) {
crm_warn("Cannot find client for token %s", token);
rc = cib_client_gone;
} else if(hash_client->channel == NULL) {
crm_err("Cannot find channel for client %s", token);
rc = cib_client_corrupt;
} else if(hash_client->channel->ops->get_chan_status(
hash_client->channel) != IPC_CONNECT) {
crm_warn("Client %s has disconnected", token);
rc = cib_client_gone;
}
}
/* this is a more important error so overwriting rc is warrented */
if(msg == NULL) {
crm_err("No message to send");
rc = cib_reply_failed;
}
if(rc == cib_ok) {
list_item = g_list_find_custom(
hash_client->delegated_calls, msg, cib_GCompareFunc);
}
if(list_item != NULL) {
/* remove it - no need to time it out */
HA_Message *orig_msg = list_item->data;
crm_debug_3("Removing msg from delegated list");
hash_client->delegated_calls = g_list_remove(
hash_client->delegated_calls, orig_msg);
CRM_DEV_ASSERT(orig_msg != msg);
crm_msg_del(orig_msg);
}
if(rc == cib_ok) {
crm_debug_3("Delivering reply to client %s", token);
if(send_ipc_message(hash_client->channel, msg) == FALSE) {
crm_warn("Delivery of reply to client %s/%s failed",
hash_client->name, token);
rc = cib_reply_failed;
}
} else {
/* be consistent...
* send_ipc_message() will free the message, so we should do
* so manually if we dont try to send it.
*/
crm_msg_del(msg);
}
return rc;
}
gint cib_GCompareFunc(gconstpointer a, gconstpointer b)
{
const HA_Message *a_msg = a;
const HA_Message *b_msg = b;
int msg_a_id = 0;
int msg_b_id = 0;
ha_msg_value_int(a_msg, F_CIB_CALLID, &msg_a_id);
ha_msg_value_int(b_msg, F_CIB_CALLID, &msg_b_id);
if(msg_a_id == msg_b_id) {
return 0;
} else if(msg_a_id < msg_b_id) {
return -1;
}
return 1;
}
gboolean
cib_msg_timeout(gpointer data)
{
crm_debug_4("Checking if any clients have timed out messages");
g_hash_table_foreach(client_list, cib_GHFunc, NULL);
return TRUE;
}
void
cib_GHFunc(gpointer key, gpointer value, gpointer user_data)
{
cib_client_t *client = value;
GListPtr list = client->delegated_calls;
HA_Message *msg = NULL;
while(list != NULL) {
int seen = 0;
int timeout = 5; /* 1 iteration == 1 seconds */
HA_Message *reply = NULL;
const char *host_to = NULL;
msg = list->data;
ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen);
ha_msg_value_int(msg, F_CIB_TIMEOUT, &timeout);
host_to = cl_get_string(msg, F_CIB_HOST);
crm_debug_4("Timeout %d, seen %d", timeout, seen);
if(timeout > 0 && seen < timeout) {
int seen2 = 0;
crm_debug_4("Updating seen count for msg from client %s",
client->id);
seen++;
ha_msg_mod_int(msg, F_CIB_SEENCOUNT, seen);
ha_msg_value_int(msg, F_CIB_SEENCOUNT, &seen2);
list = list->next;
continue;
}
crm_warn("Sending operation timeout msg to client %s",
client->id);
reply = ha_msg_new(4);
ha_msg_add(reply, F_TYPE, T_CIB);
ha_msg_add(reply, F_CIB_OPERATION,
cl_get_string(msg, F_CIB_OPERATION));
ha_msg_add(reply, F_CIB_CALLID,
cl_get_string(msg, F_CIB_CALLID));
if(host_to == NULL) {
ha_msg_add_int(reply, F_CIB_RC, cib_master_timeout);
} else {
ha_msg_add_int(reply, F_CIB_RC, cib_remote_timeout);
}
send_ipc_message(client->channel, reply);
list = list->next;
client->delegated_calls = g_list_remove(
client->delegated_calls, msg);
crm_msg_del(msg);
}
}
gboolean
cib_process_disconnect(IPC_Channel *channel, cib_client_t *cib_client)
{
if (channel->ch_status != IPC_CONNECT && cib_client != NULL) {
crm_info("Cleaning up after %s channel disconnect from client (%p) %s/%s",
cib_client->channel_name, cib_client,
crm_str(cib_client->id), crm_str(cib_client->name));
if(cib_client->id != NULL) {
g_hash_table_remove(client_list, cib_client->id);
}
if(cib_client->source != NULL) {
crm_debug_3("deleting the IPC Channel");
G_main_del_IPC_Channel(cib_client->source);
cib_client->source = NULL;
}
crm_debug_3("Freeing the cib client %s", crm_str(cib_client->id));
#if 0
/* todo - put this back in once i recheck its safe */
crm_free(cib_client->callback_id);
crm_free(cib_client->name);
crm_free(cib_client->id);
#endif
crm_free(cib_client);
crm_debug_3("Freed the cib client");
return FALSE;
} else if (channel->ch_status != IPC_CONNECT) {
crm_warn("Unknown client disconnected");
return FALSE;
}
return TRUE;
}
gboolean
cib_ha_dispatch(IPC_Channel *channel, gpointer user_data)
{
int lpc = 0;
ll_cluster_t *hb_cluster = (ll_cluster_t*)user_data;
while(lpc < 2 && hb_cluster->llc_ops->msgready(hb_cluster)) {
lpc++;
/* invoke the callbacks but dont block */
hb_cluster->llc_ops->rcvmsg(hb_cluster, 0);
}
crm_debug_4("%d HA messages dispatched", lpc);
if (channel && (channel->ch_status != IPC_CONNECT)) {
crm_crit("Lost connection to heartbeat service... exiting");
exit(100);
return FALSE;
}
return TRUE;
}
void
cib_peer_callback(const HA_Message * msg, void* private_data)
{
int call_type = 0;
const char *originator = cl_get_string(msg, F_ORIG);
if(originator == NULL || safe_str_eq(originator, cib_our_uname)) {
crm_debug_3("Discarding message %s/%s from ourselves",
cl_get_string(msg, F_CIB_CLIENTID),
cl_get_string(msg, F_CIB_CALLID));
return;
} else if(ccm_membership == NULL) {
crm_debug_3("Discarding message %s/%s: membership not established",
originator, cl_get_string(msg, F_SEQ));
return;
} else if(g_hash_table_lookup(ccm_membership, originator) == NULL) {
crm_debug_3("Discarding message %s/%s: not in our membership",
originator, cl_get_string(msg, F_CIB_CALLID));
return;
} else if(cib_get_operation_id(msg, &call_type) != cib_ok) {
crm_err("Invalid operation... discarding msg %s",
cl_get_string(msg, F_SEQ));
return;
}
crm_debug_4("%s Processing msg %s",
cib_our_uname, cl_get_string(msg, F_SEQ));
cib_process_request(msg, TRUE, TRUE, NULL);
return;
}
HA_Message *
cib_msg_copy(const HA_Message *msg, gboolean with_data)
{
int lpc = 0;
const char *field = NULL;
const char *value = NULL;
const HA_Message *value_struct = NULL;
const char *field_list[] = {
F_TYPE ,
F_CIB_CLIENTID ,
F_CIB_CALLOPTS ,
F_CIB_CALLID ,
F_CIB_OPERATION ,
F_CIB_ISREPLY ,
F_CIB_SECTION ,
F_CIB_HOST ,
F_CIB_RC ,
F_CIB_DELEGATED ,
F_CIB_OBJID ,
F_CIB_OBJTYPE ,
F_CIB_EXISTING ,
F_CIB_SEENCOUNT ,
F_CIB_TIMEOUT ,
F_CIB_CALLBACK_TOKEN ,
F_CIB_GLOBAL_UPDATE ,
F_CIB_CLIENTNAME ,
F_CIB_NOTIFY_TYPE ,
F_CIB_NOTIFY_ACTIVATE
};
const char *data_list[] = {
F_CIB_CALLDATA ,
F_CIB_UPDATE ,
F_CIB_UPDATE_RESULT
};
HA_Message *copy = ha_msg_new(10);
if(copy == NULL) {
return copy;
}
for(lpc = 0; lpc < DIMOF(field_list); lpc++) {
field = field_list[lpc];
value = cl_get_string(msg, field);
if(value != NULL) {
ha_msg_add(copy, field, value);
}
}
for(lpc = 0; with_data && lpc < DIMOF(data_list); lpc++) {
field = data_list[lpc];
value_struct = cl_get_struct(msg, field);
if(value_struct != NULL) {
ha_msg_addstruct(copy, field, value_struct);
}
}
return copy;
}
enum cib_errors
cib_get_operation_id(const HA_Message * msg, int *operation)
{
int lpc = 0;
int max_msg_types = DIMOF(cib_server_ops);
const char *op = cl_get_string(msg, F_CIB_OPERATION);
for (lpc = 0; lpc < max_msg_types; lpc++) {
if (safe_str_eq(op, cib_server_ops[lpc].operation)) {
*operation = lpc;
return cib_ok;
}
}
crm_err("Operation %s is not valid", op);
*operation = -1;
return cib_operation;
}
void
cib_client_status_callback(const char * node, const char * client,
const char * status, void * private)
{
if(safe_str_eq(client, CRM_SYSTEM_CIB)) {
crm_debug_2("Status update: Client %s/%s now has status [%s]",
node, client, status);
g_hash_table_replace(peer_hash, crm_strdup(node), crm_strdup(status));
set_connected_peers(the_cib);
}
return;
}
extern oc_ev_t *cib_ev_token;
gboolean
ccm_manual_check(gpointer data)
{
int rc = 0;
oc_ev_t *ccm_token = cib_ev_token;
crm_debug("manual check");
rc = oc_ev_handle_event(ccm_token);
if(0 == rc) {
return TRUE;
} else {
crm_err("CCM connection appears to have failed: rc=%d.", rc);
return FALSE;
}
}
gboolean cib_ccm_dispatch(int fd, gpointer user_data)
{
int rc = 0;
oc_ev_t *ccm_token = (oc_ev_t*)user_data;
crm_debug("received callback");
rc = oc_ev_handle_event(ccm_token);
if(0 == rc) {
return TRUE;
} else {
crm_err("CCM connection appears to have failed: rc=%d.", rc);
return FALSE;
}
}
void
cib_ccm_msg_callback(
oc_ed_t event, void *cookie, size_t size, const void *data)
{
int instance = -1;
gboolean update_id = FALSE;
gboolean update_quorum = FALSE;
const oc_ev_membership_t *membership = data;
if(membership != NULL) {
instance = membership->m_instance;
}
crm_info("Process CCM event=%s (id=%d)",
ccm_event_name(event), instance);
switch(event) {
case OC_EV_MS_NEW_MEMBERSHIP:
case OC_EV_MS_INVALID:
update_id = TRUE;
update_quorum = TRUE;
break;
case OC_EV_MS_PRIMARY_RESTORED:
update_id = TRUE;
break;
case OC_EV_MS_NOT_PRIMARY:
crm_debug("Ignoring transitional CCM event: %s",
ccm_event_name(event));
break;
case OC_EV_MS_EVICTED:
crm_err("Evicted from CCM: %s", ccm_event_name(event));
update_quorum = TRUE;
break;
default:
crm_err("Unknown CCM event: %d", event);
}
if(update_id) {
CRM_DEV_ASSERT(membership != NULL);
if(crm_assert_failed) { return; }
if(ccm_transition_id != NULL) {
crm_free(ccm_transition_id);
ccm_transition_id = NULL;
}
ccm_transition_id = crm_itoa(instance);
set_transition(the_cib);
}
if(update_quorum) {
- int members = 0;
+ unsigned int members = 0;
int offset = 0;
- unsigned lpc = 0;
+ unsigned int lpc = 0;
cib_have_quorum = ccm_have_quorum(event);
if(cib_have_quorum) {
crm_xml_add(
the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_TRUE);
} else {
crm_xml_add(
the_cib,XML_ATTR_HAVE_QUORUM,XML_BOOLEAN_FALSE);
}
crm_info("Quorum %s after event=%s (id=%d)",
cib_have_quorum?"(re)attained":"lost",
ccm_event_name(event), instance);
if(ccm_membership != NULL) {
g_hash_table_foreach_remove(
ccm_membership, ghash_str_clfree, NULL);
}
ccm_membership = g_hash_table_new(g_str_hash, g_str_equal);
if(membership != NULL) {
members = membership->m_n_member;
offset = membership->m_memb_idx;
}
for(lpc = 0; lpc < members; lpc++) {
oc_node_t a_node = membership->m_array[lpc+offset];
char *uname = crm_strdup(a_node.node_uname);
g_hash_table_insert(
ccm_membership, uname, uname);
}
}
oc_ev_callback_done(cookie);
return;
}
gboolean
ghash_str_clfree(gpointer key, gpointer value, gpointer user_data)
{
if(key != NULL) {
crm_free(key);
}
return TRUE;
}
gboolean
can_write(int flags)
{
const char *value = NULL;
if(cib_have_quorum) {
return TRUE;
}
value = get_crm_option(the_cib, "no_quorum_policy", TRUE);
if(safe_str_eq(value, "ignore")) {
return TRUE;
}
if((flags & cib_quorum_override) != 0) {
crm_debug_2("Overriding \"no quorum\" condition");
return TRUE;
}
return FALSE;
}
diff --git a/crm/cib/cibmon.c b/crm/cib/cibmon.c
index e6c3c1304e..18cd66a7e4 100644
--- a/crm/cib/cibmon.c
+++ b/crm/cib/cibmon.c
@@ -1,473 +1,473 @@
-/* $Id: cibmon.c,v 1.27 2005/06/17 11:08:19 andrew Exp $ */
+/* $Id: cibmon.c,v 1.28 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <hb_api.h>
#include <clplumbing/coredumps.h>
#include <clplumbing/uids.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/ctrl.h>
#include <crm/common/ipc.h>
#include <crm/cib.h>
#ifdef HAVE_GETOPT_H
# include <getopt.h>
#endif
#include <ha_msg.h> /* someone complaining about _ha_msg_mod not being found */
#include <crm/dmalloc_wrapper.h>
#define UPDATE_PREFIX "cib.updates:"
int exit_code = cib_ok;
int got_signal = 0;
GMainLoop *mainloop = NULL;
const char *crm_system_name = "cibmon";
void usage(const char *cmd, int exit_status);
void cib_connection_destroy(gpointer user_data);
void cibmon_pre_notify(const char *event, HA_Message *msg);
void cibmon_update_confirm(const char *event, HA_Message *msg);
gboolean cibmon_shutdown(int nsig, gpointer unused);
void cibmon_diff(const char *event, HA_Message *msg);
cib_t *the_cib = NULL;
#define OPTARGS "V?pPdam:"
gboolean pre_notify = FALSE;
gboolean post_notify = FALSE;
gboolean log_diffs = FALSE;
int max_failures = 30;
int
main(int argc, char **argv)
{
int argerr = 0;
int flag;
int level = 0;
int attempts = 0;
#ifdef HAVE_GETOPT_H
int option_index = 0;
static struct option long_options[] = {
/* Top-level Options */
{"verbose", 0, 0, 'V'},
{"help", 0, 0, '?'},
{"pre", 0, 0, 'p'},
{"post", 0, 0, 'P'},
{"all", 0, 0, 'a'},
{"diffs", 0, 0, 'd'},
{"max-conn-fail",1, 0, 'm'},
{0, 0, 0, 0}
};
#endif
crm_log_init(crm_system_name);
G_main_add_SignalHandler(
G_PRIORITY_HIGH, SIGTERM, cibmon_shutdown, NULL, NULL);
cl_set_corerootdir(HA_COREDIR);
cl_cdtocoredir();
while (1) {
#ifdef HAVE_GETOPT_H
flag = getopt_long(argc, argv, OPTARGS,
long_options, &option_index);
#else
flag = getopt(argc, argv, OPTARGS);
#endif
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");
printf("Long option (--%s) is not"
" (yet?) properly supported\n",
long_options[option_index].name);
++argerr;
break;
#endif
case 'V':
level = get_crm_log_level();
cl_log_enable_stderr(TRUE);
set_crm_log_level(level+1);
break;
case '?':
usage(crm_system_name, LSB_EXIT_OK);
break;
case 'm':
max_failures = crm_atoi(optarg, "30");
break;
case 'a':
pre_notify = TRUE;
post_notify = TRUE;
log_diffs = TRUE;
break;
case 'd':
log_diffs = TRUE;
break;
case 'p':
pre_notify = TRUE;
break;
case 'P':
post_notify = TRUE;
break;
default:
printf("Argument code 0%o (%c)"
" is not (?yet?) supported\n",
flag, 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) {
usage(crm_system_name, LSB_EXIT_GENERIC);
}
the_cib = cib_new();
do {
if(attempts != 0) {
sleep(1);
}
exit_code = the_cib->cmds->signon(
the_cib, crm_system_name, cib_query);
} while(exit_code == cib_connection && attempts++ < max_failures);
if(exit_code != cib_ok) {
crm_err("Signon to CIB failed: %s",
cib_error2string(exit_code));
}
if(exit_code == cib_ok) {
crm_debug("Setting dnotify");
exit_code = the_cib->cmds->set_connection_dnotify(
the_cib, cib_connection_destroy);
}
if(exit_code == cib_ok && pre_notify) {
crm_debug("Setting pre-notify callback");
exit_code = the_cib->cmds->add_notify_callback(
the_cib, T_CIB_PRE_NOTIFY, cibmon_pre_notify);
if(exit_code != cib_ok) {
crm_err("Failed to set %s callback: %s",
T_CIB_PRE_NOTIFY, cib_error2string(exit_code));
}
}
if(exit_code == cib_ok && post_notify) {
crm_debug("Setting post-notify callback");
exit_code = the_cib->cmds->add_notify_callback(
the_cib, T_CIB_UPDATE_CONFIRM, cibmon_update_confirm);
if(exit_code != cib_ok) {
crm_err("Failed to set %s callback: %s",
T_CIB_UPDATE_CONFIRM, cib_error2string(exit_code));
}
}
if(exit_code == cib_ok && log_diffs) {
crm_debug("Setting diff callback");
exit_code = the_cib->cmds->add_notify_callback(
the_cib, T_CIB_DIFF_NOTIFY, cibmon_diff);
if(exit_code != cib_ok) {
crm_err("Failed to set %s callback: %s",
T_CIB_DIFF_NOTIFY, cib_error2string(exit_code));
}
}
if(exit_code != cib_ok) {
crm_err("Setup failed, could not monitor CIB actions");
return -exit_code;
}
mainloop = g_main_new(FALSE);
crm_info("Starting mainloop");
g_main_run(mainloop);
crm_debug_3("%s exiting normally", crm_system_name);
fflush(stderr);
return -exit_code;
}
void
usage(const char *cmd, int exit_status)
{
FILE *stream;
stream = exit_status != 0 ? stderr : stdout;
#if 0
fprintf(stream, "usage: %s [-?Vio] command\n"
"\twhere necessary, XML data will be expected using -X"
" or on STDIN if -X isnt specified\n", cmd);
fprintf(stream, "Options\n");
fprintf(stream, "\t--%s (-%c) <id>\tid of the object being operated on\n",
XML_ATTR_ID, 'i');
fprintf(stream, "\t--%s (-%c) <type>\tobject type being operated on\n",
"obj_type", 'o');
fprintf(stream, "\t--%s (-%c)\tturn on debug info."
" additional instance increase verbosity\n", "verbose", 'V');
fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?');
fprintf(stream, "\nCommands\n");
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ERASE, 'E');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_CREATE, 'C');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_REPLACE,'R');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_UPDATE, 'U');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ISMASTER,'M');
fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_SYNC, 'S');
fprintf(stream, "\nXML data\n");
fprintf(stream, "\t--%s (-%c) <string>\t\n", F_CRM_DATA, 'X');
fprintf(stream, "\nAdvanced Options\n");
fprintf(stream, "\t--%s (-%c)\tsend command to specified host."
" Applies to %s and %s commands only\n", "host", 'h',
CIB_OP_QUERY, CRM_OP_CIB_SYNC);
fprintf(stream, "\t--%s (-%c)\tcommand only takes effect locally"
" on the specified host\n", "local", 'l');
fprintf(stream, "\t--%s (-%c)\twait for call to complete before"
" returning\n", "sync-call", 's');
#endif
fflush(stream);
exit(exit_status);
}
void
cib_connection_destroy(gpointer user_data)
{
crm_err("Connection to the CIB terminated... exiting");
g_main_quit(mainloop);
return;
}
int update_depth = 0;
gboolean last_notify_pre = TRUE;
void
cibmon_pre_notify(const char *event, HA_Message *msg)
{
int rc = -1;
const char *op = NULL;
const char *id = NULL;
const char *type = NULL;
crm_data_t *update = NULL;
crm_data_t *pre_update = NULL;
if(msg == NULL) {
crm_err("NULL update");
return;
}
op = cl_get_string(msg, F_CIB_OPERATION);
id = cl_get_string(msg, F_CIB_OBJID);
type = cl_get_string(msg, F_CIB_OBJTYPE);
ha_msg_value_int(msg, F_CIB_RC, &rc);
update_depth++;
last_notify_pre = TRUE;
update = get_message_xml(msg, F_CIB_UPDATE);
pre_update = get_message_xml(msg, F_CIB_EXISTING);
if(update != NULL) {
crm_debug_3(UPDATE_PREFIX"[%s] Performing %s on <%s%s%s>",
event, op, type, id?" id=":"", id?id:"");
print_xml_formatted(LOG_DEBUG_5, UPDATE_PREFIX,
update, "Update");
} else if(update == NULL) {
crm_info(UPDATE_PREFIX"[%s] Performing operation %s (on section=%s)",
event, op, crm_str(type));
}
print_xml_formatted(LOG_DEBUG_3, UPDATE_PREFIX,
pre_update, "Existing Object");
free_xml(update);
free_xml(pre_update);
}
void
cibmon_update_confirm(const char *event, HA_Message *msg)
{
int rc = -1;
const char *op = NULL;
const char *id = NULL;
const char *type = NULL;
crm_data_t *update = NULL;
crm_data_t *output = NULL;
crm_data_t *generation = NULL;
if(msg == NULL) {
crm_err("NULL update");
return;
}
op = cl_get_string(msg, F_CIB_OPERATION);
id = cl_get_string(msg, F_CIB_OBJID);
type = cl_get_string(msg, F_CIB_OBJTYPE);
update_depth--;
last_notify_pre = FALSE;
ha_msg_value_int(msg, F_CIB_RC, &rc);
update = get_message_xml(msg, F_CIB_UPDATE);
output = get_message_xml(msg, F_CIB_UPDATE_RESULT);
generation = get_message_xml(msg, "cib_generation");
if(update == NULL) {
if(rc == cib_ok) {
crm_debug_2(UPDATE_PREFIX"[%s] %s (to %s) confirmed",
event, op, crm_str(type));
} else {
crm_warn(UPDATE_PREFIX"[%s] %s (to %s) ABORTED: (%d) %s",
event, op, crm_str(type), rc,
cib_error2string(rc));
}
} else {
if(rc == cib_ok) {
crm_debug_2(UPDATE_PREFIX"[%s] Operation %s to <%s%s%s> confirmed.",
event, op, crm_str(type),
id?" id=":"", id?id:"");
} else {
crm_warn(UPDATE_PREFIX"[%s] Operation %s to <%s %s%s> ABORTED: (%d) %s",
event, op, crm_str(type), id?" id=":"", id?id:"",
rc, cib_error2string(rc));
}
}
if(update != NULL) {
print_xml_formatted(
rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX,
update, "Update");
}
print_xml_formatted(
rc==cib_ok?LOG_DEBUG_3:LOG_WARNING, UPDATE_PREFIX,
output, "Resulting Object");
if(update_depth == 0) {
print_xml_formatted(
rc==cib_ok?LOG_DEBUG:LOG_WARNING, UPDATE_PREFIX,
generation, "CIB Generation");
}
free_xml(update);
free_xml(output);
free_xml(generation);
}
void
cibmon_diff(const char *event, HA_Message *msg)
{
int rc = -1;
const char *op = NULL;
crm_data_t *diff = NULL;
crm_data_t *update = get_message_xml(msg, F_CIB_UPDATE);
- int log_level = LOG_INFO;
+ unsigned int log_level = LOG_INFO;
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);
diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
if(rc < cib_ok) {
log_level = LOG_WARNING;
crm_log_maybe(log_level, "[%s] %s ABORTED: %s",
event, op, cib_error2string(rc));
} else {
crm_log_maybe(log_level, "[%s] %s confirmed", event, op);
}
log_cib_diff(log_level, diff, op);
if(update != NULL) {
print_xml_formatted(
log_level+2, "raw_update", update, NULL);
}
free_xml(diff);
free_xml(update);
}
gboolean
cibmon_shutdown(int nsig, gpointer unused)
{
got_signal = 1;
if (mainloop != NULL && g_main_is_running(mainloop)) {
g_main_quit(mainloop);
} else {
exit(LSB_EXIT_OK);
}
return TRUE;
}
diff --git a/crm/cib/messages.c b/crm/cib/messages.c
index 772cfd8b4a..1a604bd976 100644
--- a/crm/cib/messages.c
+++ b/crm/cib/messages.c
@@ -1,898 +1,898 @@
-/* $Id: messages.c,v 1.47 2005/06/27 08:17:06 andrew Exp $ */
+/* $Id: messages.c,v 1.48 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <heartbeat.h>
#include <clplumbing/cl_log.h>
#include <time.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <cibio.h>
#include <cibmessages.h>
#include <cibprimatives.h>
#include <callbacks.h>
#include <crm/dmalloc_wrapper.h>
extern const char *cib_our_uname;
extern gboolean syncd_once;
enum cib_errors revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags);
int get_revision(crm_data_t *xml_obj, int cur_revision);
enum cib_errors updateList(
crm_data_t *local_cib, crm_data_t *update_command, crm_data_t *failed,
int operation, const char *section);
crm_data_t *createCibFragmentAnswer(const char *section, crm_data_t *failed);
enum cib_errors replace_section(
const char *section, crm_data_t *tmpCib, crm_data_t *command);
gboolean check_generation(crm_data_t *newCib, crm_data_t *oldCib);
gboolean update_results(
crm_data_t *failed, crm_data_t *target, int operation, int return_code);
enum cib_errors cib_update_counter(
crm_data_t *xml_obj, const char *field, gboolean reset);
enum cib_errors sync_our_cib(HA_Message *request, gboolean all);
enum cib_errors
cib_process_default(
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;
crm_debug_2("Processing \"%s\" event", op);
if(answer != NULL) { *answer = NULL; }
if(op == NULL) {
result = cib_operation;
crm_err("No operation specified");
} else if(strcmp(CRM_OP_NOOP, op) == 0) {
;
} else {
result = cib_NOTSUPPORTED;
crm_err("Action [%s] is not supported by the CIB", op);
}
return result;
}
enum cib_errors
cib_process_quit(
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;
crm_debug_2("Processing \"%s\" event", op);
crm_warn("The CRMd has asked us to exit... complying");
exit(0);
return result;
}
enum cib_errors
cib_process_readwrite(
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;
crm_debug_2("Processing \"%s\" event", op);
if(safe_str_eq(op, CIB_OP_ISMASTER)) {
if(cib_is_master == TRUE) {
result = cib_ok;
} else {
result = cib_not_master;
}
return result;
}
if(safe_str_eq(op, CIB_OP_MASTER)) {
if(cib_is_master == FALSE) {
crm_info("We are now in R/W mode");
cib_is_master = TRUE;
syncd_once = TRUE;
} else {
crm_debug("We are still in R/W mode");
}
} else if(cib_is_master) {
crm_info("We are now in R/O mode");
cib_is_master = FALSE;
}
return result;
}
enum cib_errors
cib_process_ping(
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;
crm_debug_2("Processing \"%s\" event", op);
if(answer != NULL) {
*answer = createPingAnswerFragment(CRM_SYSTEM_CIB, "ok");
}
return result;
}
enum cib_errors
cib_process_query(
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)
{
crm_data_t *obj_root = NULL;
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for section=%s",
op, crm_str(section));
if(answer != NULL) { *answer = NULL; }
else { return cib_output_ptr; }
if (safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
*answer = create_xml_node(NULL, XML_TAG_FRAGMENT);
/* crm_xml_add(*answer, XML_ATTR_SECTION, section); */
obj_root = get_object_root(section, existing_cib);
if(obj_root == NULL) {
result = cib_NOTEXISTS;
} else if(obj_root == existing_cib) {
crm_xml_add(obj_root, "origin", cib_our_uname);
add_node_copy(*answer, obj_root);
} else {
crm_data_t *cib = createEmptyCib();
crm_data_t *query_obj_root = get_object_root(section, cib);
copy_in_properties(cib, existing_cib);
crm_xml_add(cib, "origin", cib_our_uname);
xml_child_iter(
obj_root, an_obj, NULL,
add_node_copy(query_obj_root, an_obj);
);
add_node_copy(*answer, cib);
free_xml(cib);
}
if(result == cib_ok && *answer == NULL) {
crm_err("Error creating query response");
result = cib_output_data;
}
return result;
}
enum cib_errors
cib_process_erase(
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;
crm_debug_2("Processing \"%s\" event", op);
if(answer != NULL) { *answer = NULL; }
*result_cib = createEmptyCib();
result = revision_check(existing_cib, *result_cib, options);
copy_in_properties(*result_cib, existing_cib);
if(result == cib_ok && !(options & cib_inhibit_bcast)) {
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, TRUE);
}
if(answer != NULL) {
*answer = createCibFragmentAnswer(NULL, NULL);
}
return result;
}
enum cib_errors
cib_process_bump(
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;
crm_debug_2("Processing \"%s\" event for epoche=%s",
op, crm_str(crm_element_value(the_cib, XML_ATTR_GENERATION)));
if(answer != NULL) { *answer = NULL; }
*result_cib = copy_xml(the_cib);
cib_update_counter(*result_cib, XML_ATTR_GENERATION, FALSE);
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
if(answer != NULL) {
*answer = createCibFragmentAnswer(NULL, NULL);
}
return result;
}
extern ll_cluster_t *hb_conn;
extern HA_Message *cib_msg_copy(const HA_Message *msg, gboolean with_data);
enum cib_errors
cib_process_sync(
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)
{
return sync_our_cib(input, TRUE);
}
enum cib_errors
cib_process_sync_one(
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)
{
return sync_our_cib(input, FALSE);
}
enum cib_errors
cib_update_counter(crm_data_t *xml_obj, const char *field, gboolean reset)
{
char *new_value = NULL;
char *old_value = NULL;
int int_value = -1;
/* modify the timestamp */
set_node_tstamp(xml_obj);
if(reset == FALSE && crm_element_value(xml_obj, field) != NULL) {
old_value = crm_element_value_copy(xml_obj, field);
}
if(old_value != NULL) {
crm_malloc0(new_value, 128*(sizeof(char)));
int_value = atoi(old_value);
sprintf(new_value, "%d", ++int_value);
} else {
new_value = crm_strdup("1");
}
crm_debug_4("%s %d(%s)->%s",
field, int_value, crm_str(old_value), crm_str(new_value));
crm_xml_add(xml_obj, field, new_value);
crm_free(new_value);
crm_free(old_value);
return cib_ok;
}
enum cib_errors
cib_process_diff(
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)
{
- int log_level = LOG_DEBUG;
+ unsigned int log_level = LOG_DEBUG;
const char *value = NULL;
const char *reason = NULL;
gboolean apply_diff = TRUE;
gboolean do_resync = FALSE;
enum cib_errors result = cib_ok;
int this_updates = 0;
int this_epoche = 0;
int this_admin_epoche = 0;
int diff_add_updates = 0;
int diff_add_epoche = 0;
int diff_add_admin_epoche = 0;
int diff_del_updates = 0;
int diff_del_epoche = 0;
int diff_del_admin_epoche = 0;
crm_debug_2("Processing \"%s\" event", op);
value = crm_element_value(existing_cib, XML_ATTR_GENERATION);
this_epoche = atoi(value?value:"0");
value = crm_element_value(existing_cib, XML_ATTR_NUMUPDATES);
this_updates = atoi(value?value:"0");
value = crm_element_value(existing_cib, XML_ATTR_GENERATION_ADMIN);
this_admin_epoche = atoi(value?value:"0");
cib_diff_version_details(
input,
&diff_add_admin_epoche, &diff_add_epoche, &diff_add_updates,
&diff_del_admin_epoche, &diff_del_epoche, &diff_del_updates);
if(diff_del_admin_epoche == diff_add_admin_epoche
&& diff_del_epoche == diff_add_epoche
&& diff_del_updates == diff_add_updates) {
apply_diff = FALSE;
log_level = LOG_ERR;
reason = "+ and - versions in the diff did not change";
log_cib_diff(LOG_ERR, input, __FUNCTION__);
}
if(apply_diff && diff_del_admin_epoche > this_admin_epoche) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is less than required";
} else if(apply_diff && diff_del_admin_epoche < this_admin_epoche) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION_ADMIN"\" is greater than required";
}
if(apply_diff && diff_del_epoche > this_epoche) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_GENERATION"\" is less than required";
} else if(apply_diff && diff_del_epoche < this_epoche) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_GENERATION"\" is greater than required";
}
if(apply_diff && diff_del_updates > this_updates) {
do_resync = TRUE;
apply_diff = FALSE;
log_level = LOG_INFO;
reason = "current \""XML_ATTR_NUMUPDATES"\" is less than required";
} else if(apply_diff && diff_del_updates < this_updates) {
apply_diff = FALSE;
log_level = LOG_WARNING;
reason = "current \""XML_ATTR_NUMUPDATES"\" is greater than required";
}
if(apply_diff
&& apply_cib_diff(existing_cib, input, result_cib) == FALSE) {
log_level = LOG_WARNING;
reason = "Failed application of an update diff";
if(options & cib_force_diff && cib_is_master == FALSE) {
log_level = LOG_INFO;
reason = "Failed application of a global update. Requesting full refresh.";
do_resync = TRUE;
} else if(options & cib_force_diff) {
reason = "Failed application of a global update. Not requesting full refresh.";
}
}
if(reason != NULL) {
crm_log_maybe(
log_level,
"Diff %d.%d.%d -> %d.%d.%d not applied to %d.%d.%d: %s",
diff_del_admin_epoche,diff_del_epoche,diff_del_updates,
diff_add_admin_epoche,diff_add_epoche,diff_add_updates,
this_admin_epoche,this_epoche,this_updates, reason);
result = cib_diff_failed;
}
if(do_resync && cib_is_master == FALSE) {
HA_Message *sync_me = ha_msg_new(2);
free_xml(*result_cib);
*result_cib = NULL;
result = cib_diff_resync;
crm_info("Requesting re-sync from peer: %s", reason);
ha_msg_add(sync_me, F_TYPE, "cib");
ha_msg_add(sync_me, F_CIB_OPERATION, CIB_OP_SYNC_ONE);
ha_msg_add(sync_me, F_CIB_DELEGATED, cib_our_uname);
if(send_ha_message(hb_conn, sync_me, NULL) == FALSE) {
result = cib_not_connected;
}
ha_msg_del(sync_me);
} else if(do_resync) {
crm_err("Not resyncing in master mode");
}
return result;
}
enum cib_errors
cib_process_replace(
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)
{
gboolean verbose = FALSE;
enum cib_errors result = cib_ok;
crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
if(answer != NULL) { *answer = NULL; }
if (options & cib_verbose) {
verbose = TRUE;
}
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
if (input == NULL) {
result = cib_NOOBJECT;
} else if(section == NULL) {
int updates = 0;
int epoche = 0;
int admin_epoche = 0;
int replace_updates = 0;
int replace_epoche = 0;
int replace_admin_epoche = 0;
const char *reason = NULL;
cib_version_details(
existing_cib, &admin_epoche, &epoche, &updates);
cib_version_details(input, &replace_admin_epoche,
&replace_epoche, &replace_updates);
if(replace_admin_epoche < admin_epoche) {
reason = XML_ATTR_GENERATION_ADMIN;
} else if(replace_admin_epoche > admin_epoche) {
/* no more checks */
} else if(replace_epoche < epoche) {
reason = XML_ATTR_GENERATION;
} else if(replace_epoche > epoche) {
/* no more checks */
} else if(replace_updates < updates) {
reason = XML_ATTR_NUMUPDATES;
}
if(reason != NULL) {
crm_warn("Replacement %d.%d.%d not applied to %d.%d.%d:"
" current %s is greater than the replacement",
replace_admin_epoche, replace_epoche,
replace_updates, admin_epoche, epoche, updates,
reason);
result = cib_old_data;
}
*result_cib = copy_xml(input);
} else {
*result_cib = copy_xml(existing_cib);
result = replace_section(section, *result_cib, input);
}
if(result == cib_ok && section != NULL) {
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
}
if (answer != NULL && (verbose || result != cib_ok)) {
*answer = createCibFragmentAnswer(section, NULL);
}
return result;
}
enum cib_errors
cib_process_delete(
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)
{
crm_debug_2("Processing \"%s\" event", op);
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
*result_cib = copy_xml(existing_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
if(delete_xml_child(NULL, *result_cib, input) == FALSE) {
return cib_NOTEXISTS;
}
return cib_ok;
}
enum cib_errors
cib_process_modify(
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)
{
gboolean verbose = FALSE;
crm_data_t *failed = NULL;
enum cib_errors result = cib_ok;
int cib_update_op = CIB_UPDATE_OP_NONE;
crm_debug_2("Processing \"%s\" event for section=%s", op, crm_str(section));
failed = create_xml_node(NULL, XML_TAG_FAILED);
if (strcmp(CIB_OP_CREATE, op) == 0) {
cib_update_op = CIB_UPDATE_OP_ADD;
} else if (strcmp(CIB_OP_UPDATE, op) == 0) {
cib_update_op = CIB_UPDATE_OP_MODIFY;
} else if (strcmp(CIB_OP_DELETE_ALT, op) == 0) {
cib_update_op = CIB_UPDATE_OP_DELETE;
} else {
crm_err("Incorrect request handler invoked for \"%s\" op",
crm_str(op));
return cib_operation;
}
result = cib_ok;
if (options & cib_verbose) {
verbose = TRUE;
}
if(safe_str_eq(XML_CIB_TAG_SECTION_ALL, section)) {
section = NULL;
}
if(input == NULL) {
crm_err("Cannot perform modification with no data");
return cib_NOOBJECT;
}
*result_cib = copy_xml(existing_cib);
crm_validate_data(input);
crm_validate_data(*result_cib);
/* make changes to a temp copy then activate */
if(section == NULL) {
crm_data_t *sub_input = NULL;
copy_in_properties(*result_cib, input);
/* order is no longer important here */
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_NODES);
}
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_RESOURCES);
}
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_CONSTRAINTS);
}
if(result == cib_ok) {
sub_input = get_object_root(XML_CIB_TAG_NODES, input);
result = updateList(
*result_cib, sub_input, failed, cib_update_op,
XML_CIB_TAG_STATUS);
}
} else {
result = updateList(
*result_cib, input, failed, cib_update_op, section);
}
if(result == cib_ok && !(options & cib_inhibit_bcast)) {
cib_update_counter(*result_cib, XML_ATTR_NUMUPDATES, FALSE);
}
if (result != cib_ok || xml_has_children(failed)) {
if(result == cib_ok) {
result = cib_unknown;
}
crm_log_xml_err(failed, "CIB Update failures");
}
if (verbose || xml_has_children(failed) || result != cib_ok) {
*answer = createCibFragmentAnswer(section, failed);
}
free_xml(failed);
return result;
}
enum cib_errors
replace_section(
const char *section, crm_data_t *tmpCib, crm_data_t *new_section)
{
crm_data_t *old_section = NULL;
/* find the old and new versions of the section */
old_section = get_object_root(section, tmpCib);
if(old_section == NULL) {
crm_err("The CIB is corrupt, cannot replace missing section %s",
section);
return cib_NOSECTION;
} else if(new_section == NULL) {
crm_err("The CIB is corrupt, cannot set section %s to nothing",
section);
return cib_NOSECTION;
}
xml_child_iter(
old_section, a_child, NULL,
free_xml_from_parent(old_section, a_child);
);
copy_in_properties(old_section, new_section);
xml_child_iter(
new_section, a_child, NULL,
add_node_copy(old_section, a_child);
);
return cib_ok;
}
enum cib_errors
updateList(crm_data_t *local_cib, crm_data_t *xml_section, crm_data_t *failed,
int operation, const char *section)
{
int rc = cib_ok;
crm_data_t *this_section = get_object_root(section, local_cib);
if (section == NULL || xml_section == NULL) {
crm_err("Section %s not found in message."
" CIB update is corrupt, ignoring.",
crm_str(section));
return cib_NOSECTION;
}
if((CIB_UPDATE_OP_NONE > operation) || (operation > CIB_UPDATE_OP_MAX)){
crm_err("Invalid operation on section %s", crm_str(section));
return cib_operation;
}
set_node_tstamp(this_section);
xml_child_iter(
xml_section, a_child, NULL,
rc = cib_ok;
if(operation == CIB_UPDATE_OP_DELETE) {
rc = delete_cib_object(this_section, a_child);
update_results(failed, a_child, operation, rc);
} else if(operation == CIB_UPDATE_OP_MODIFY) {
rc = update_cib_object(this_section, a_child);
update_results(failed, a_child, operation, rc);
} else {
rc = add_cib_object(this_section, a_child);
update_results(failed, a_child, operation, rc);
}
);
if(rc == cib_ok && xml_has_children(failed)) {
rc = cib_unknown;
}
return rc;
}
crm_data_t*
createCibFragmentAnswer(const char *section, crm_data_t *failed)
{
crm_data_t *cib = NULL;
crm_data_t *fragment = NULL;
fragment = create_xml_node(NULL, XML_TAG_FRAGMENT);
if (section == NULL
|| strlen(section) == 0
|| strcmp(XML_CIB_TAG_SECTION_ALL, section) == 0) {
cib = get_the_CIB();
if(cib != NULL) {
add_node_copy(fragment, get_the_CIB());
}
} else {
crm_data_t *obj_root = get_object_root(section, get_the_CIB());
if(obj_root != NULL) {
cib = create_xml_node(fragment, XML_TAG_CIB);
add_node_copy(cib, obj_root);
copy_in_properties(cib, get_the_CIB());
}
}
if (failed != NULL && xml_has_children(failed)) {
add_node_copy(fragment, failed);
}
crm_xml_add(fragment, XML_ATTR_SECTION, section);
crm_xml_add(fragment, "generated_on", cib_our_uname);
return fragment;
}
gboolean
check_generation(crm_data_t *newCib, crm_data_t *oldCib)
{
if(cib_compare_generation(newCib, oldCib) >= 0) {
return TRUE;
}
crm_warn("Generation from update is older than the existing one");
return FALSE;
}
gboolean
update_results(
crm_data_t *failed, crm_data_t *target, int operation, int return_code)
{
gboolean was_error = FALSE;
const char *error_msg = NULL;
const char *operation_msg = NULL;
crm_data_t *xml_node = NULL;
operation_msg = cib_op2string(operation);
if (return_code != cib_ok) {
error_msg = cib_error2string(return_code);
xml_node = create_xml_node(failed, XML_FAIL_TAG_CIB);
was_error = TRUE;
add_node_copy(xml_node, target);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_ID, ID(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OBJTYPE, TYPE(target));
crm_xml_add(xml_node, XML_FAILCIB_ATTR_OP, operation_msg);
crm_xml_add(xml_node, XML_FAILCIB_ATTR_REASON, error_msg);
crm_warn("Action %s failed: %s (cde=%d)",
operation_msg, error_msg, return_code);
} else {
crm_debug_3("CIB %s passed", operation_msg);
}
return was_error;
}
enum cib_errors
revision_check(crm_data_t *cib_update, crm_data_t *cib_copy, int flags)
{
enum cib_errors rc = cib_ok;
char *revision = crm_element_value_copy(
cib_update, XML_ATTR_CIB_REVISION);
const char *cur_revision = crm_element_value(
cib_copy, XML_ATTR_CIB_REVISION);
crm_validate_data(cib_update);
crm_validate_data(cib_copy);
if(revision == NULL) {
return cib_ok;
} else if(cur_revision == NULL
|| strcmp(revision, cur_revision) > 0) {
crm_info("Updating CIB revision to %s", revision);
crm_xml_add(
cib_copy, XML_ATTR_CIB_REVISION, revision);
} else {
/* make sure we end up with the right value in the end */
crm_xml_add(
cib_update, XML_ATTR_CIB_REVISION, cur_revision);
}
if(strcmp(revision, cib_feature_revision_s) > 0) {
CRM_DEV_ASSERT(cib_is_master == FALSE);
CRM_DEV_ASSERT((flags & cib_scope_local) == 0);
if(cib_is_master) {
crm_err("Update uses an unsupported tag/feature:"
" %s vs %s",
revision, cib_feature_revision_s);
rc = cib_revision_unsupported;
} else if(flags & cib_scope_local) {
/* an admin has forced a local change using a tag we
* dont understand... ERROR
*/
crm_err("Local update uses an unsupported tag/feature:"
" %s vs %s",
revision, cib_feature_revision_s);
rc = cib_revision_unsupported;
}
}
crm_free(revision);
return rc;
}
enum cib_errors
sync_our_cib(HA_Message *request, gboolean all)
{
enum cib_errors result = cib_ok;
const char *host = cl_get_string(request, F_ORIG);
const char *op = cl_get_string(request, F_CIB_OPERATION);
crm_data_t *sync_data = create_cib_fragment(the_cib, NULL);
HA_Message *replace_request = cib_msg_copy(request, FALSE);
CRM_DEV_ASSERT(sync_data != NULL);
CRM_DEV_ASSERT(replace_request != NULL);
crm_info("Syncing CIB to %s", all?"all peers":host);
if(all == FALSE && host == NULL) {
crm_log_message(LOG_ERR, request);
}
if(all == FALSE && host != NULL) {
ha_msg_add(replace_request, F_CIB_ISREPLY, host);
}
ha_msg_mod(replace_request, F_CIB_OPERATION, CIB_OP_REPLACE);
ha_msg_add(replace_request, "original_"F_CIB_OPERATION, op);
ha_msg_add(replace_request, F_CIB_GLOBAL_UPDATE, XML_BOOLEAN_TRUE);
ha_msg_addstruct(replace_request, F_CIB_CALLDATA, sync_data);
if(send_ha_message(hb_conn, replace_request, all?NULL:host) == FALSE) {
result = cib_not_connected;
}
ha_msg_del(replace_request);
free_xml(sync_data);
return result;
}
diff --git a/crm/crmd/ccm.c b/crm/crmd/ccm.c
index a9f468d462..f8b1e7330a 100644
--- a/crm/crmd/ccm.c
+++ b/crm/crmd/ccm.c
@@ -1,655 +1,656 @@
-/* $Id: ccm.c,v 1.85 2005/06/17 18:44:57 andrew Exp $ */
+/* $Id: ccm.c,v 1.86 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
/* put these first so that uuid_t is defined without conflicts */
#include <portability.h>
#include <ocf/oc_event.h>
#include <ocf/oc_membership.h>
#include <clplumbing/GSource.h>
#include <string.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_fsa.h>
#include <fsa_proto.h>
#include <crmd_callbacks.h>
#include <crm/dmalloc_wrapper.h>
void oc_ev_special(const oc_ev_t *, oc_ev_class_t , int );
int register_with_ccm(ll_cluster_t *hb_cluster);
void msg_ccm_join(const HA_Message *msg, void *foo);
void crmd_ccm_msg_callback(oc_ed_t event,
void *cookie,
size_t size,
const void *data);
gboolean ghash_node_clfree(gpointer key, gpointer value, gpointer user_data);
void ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data);
#define CCM_EVENT_DETAIL 0
#define CCM_EVENT_DETAIL_PARTIAL 1
oc_ev_t *fsa_ev_token;
int num_ccm_register_fails = 0;
int max_ccm_register_fails = 30;
/* A_CCM_CONNECT */
enum crmd_fsa_input
do_ccm_control(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 ret;
int fsa_ev_fd;
gboolean did_fail = FALSE;
if(action & A_CCM_DISCONNECT){
oc_ev_unregister(fsa_ev_token);
}
if(action & A_CCM_CONNECT) {
crm_debug_3("Registering with CCM");
ret = oc_ev_register(&fsa_ev_token);
if (ret != 0) {
crm_warn("CCM registration failed");
did_fail = TRUE;
}
if(did_fail == FALSE) {
crm_debug_3("Setting up CCM callbacks");
ret = oc_ev_set_callback(fsa_ev_token, OC_EV_MEMB_CLASS,
crmd_ccm_msg_callback, NULL);
if (ret != 0) {
crm_warn("CCM callback not set");
did_fail = TRUE;
}
}
if(did_fail == FALSE) {
oc_ev_special(fsa_ev_token, OC_EV_MEMB_CLASS, 0/*don't care*/);
crm_debug_3("Activating CCM token");
ret = oc_ev_activate(fsa_ev_token, &fsa_ev_fd);
if (ret != 0){
crm_warn("CCM Activation failed");
did_fail = TRUE;
}
}
if(did_fail) {
num_ccm_register_fails++;
oc_ev_unregister(fsa_ev_token);
if(num_ccm_register_fails < max_ccm_register_fails) {
crm_warn("CCM Connection failed"
" %d times (%d max)",
num_ccm_register_fails,
max_ccm_register_fails);
crm_timer_start(wait_timer);
crmd_fsa_stall(NULL);
return I_NULL;
} else {
crm_err("CCM Activation failed %d (max) times",
num_ccm_register_fails);
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
}
crm_info("CCM Activation passed... all set to go!");
G_main_add_fd(G_PRIORITY_HIGH, fsa_ev_fd, FALSE, ccm_dispatch,
fsa_ev_token, default_ipc_connection_destroy);
}
if(action & ~(A_CCM_CONNECT|A_CCM_DISCONNECT)) {
crm_err("Unexpected action %s in %s",
fsa_action2string(action), __FUNCTION__);
}
return I_NULL;
}
/* A_CCM_EVENT */
enum crmd_fsa_input
do_ccm_event(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)
{
enum crmd_fsa_input return_input = I_NULL;
oc_ed_t event;
const oc_ev_membership_t *oc = NULL;
struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
if(ccm_data == NULL) {
crm_err("No data provided to FSA function");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
} else if(msg_data->fsa_cause != C_CCM_CALLBACK) {
crm_err("FSA function called in response to incorect input");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
event = ccm_data->event;
oc = ccm_data->oc;
ccm_event_detail(oc, event);
if (OC_EV_MS_EVICTED == event) {
/* todo: drop back to S_PENDING instead */
/* get out... NOW!
*
* go via the error recovery process so that HA will
* restart us if required
*/
register_fsa_error(cause, I_ERROR, msg_data->data);
return I_NULL;
}
CRM_DEV_ASSERT(oc->m_n_in != 0 || oc->m_n_out != 0);
if(AM_I_DC) {
/* Membership changed, remind everyone we're here.
* This will aid detection of duplicate DCs
*/
HA_Message *no_op = create_request(
CRM_OP_NOOP, NULL, NULL,
CRM_SYSTEM_DC, CRM_SYSTEM_CRMD, NULL);
send_msg_via_ha(fsa_cluster_conn, no_op);
} else if(oc->m_n_out != 0) {
/* Possibly move this logic to ghash_update_cib_node() */
unsigned lpc = 0;
int offset = oc->m_out_idx;
for(lpc=0; lpc < oc->m_n_out; lpc++) {
const char *uname = oc->m_array[offset+lpc].node_uname;
if(uname == NULL) {
crm_err("CCM node had no name");
continue;
} else if(safe_str_eq(uname, fsa_our_dc)) {
crm_warn("Our DC node (%s) left the cluster",
uname);
register_fsa_input(cause, I_ELECTION, NULL);
}
}
}
return return_input;
}
/* A_CCM_UPDATE_CACHE */
/*
* Take the opportunity to update the node status in the CIB as well
*/
enum crmd_fsa_input
do_ccm_update_cache(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)
{
enum crmd_fsa_input next_input = I_NULL;
- int lpc, offset;
+ unsigned int lpc;
+ int offset;
GHashTable *members = NULL;
oc_ed_t event;
const oc_ev_membership_t *oc = NULL;
oc_node_list_t *tmp = NULL, *membership_copy = NULL;
struct crmd_ccm_data_s *ccm_data = fsa_typed_data(fsa_dt_ccm);
if(ccm_data == NULL) {
crm_err("No data provided to FSA function");
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
return I_NULL;
}
event = ccm_data->event;
oc = ccm_data->oc;
crm_debug_2("Updating CCM cache after a \"%s\" event.",
ccm_event_name(event));
crm_debug_2("instance=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
"new_idx=%d, old_idx=%d",
oc->m_instance,
oc->m_n_member,
oc->m_n_in,
oc->m_n_out,
oc->m_memb_idx,
oc->m_in_idx,
oc->m_out_idx);
#define ALAN_DEBUG 1
#ifdef ALAN_DEBUG
{
/*
* Size (Size + 2) / 2
*
* 3 (3+2)/2 = 5 / 2 = 2
* 4 (4+2)/2 = 6 / 2 = 3
* 5 (5+2)/2 = 7 / 2 = 3
* 6 (6+2)/2 = 8 / 2 = 4
* 7 (7+2)/2 = 9 / 2 = 4
*/
- int clsize = (oc->m_out_idx - oc->m_n_member);
- int plsize = (clsize + 2)/2;
+ unsigned int clsize = (oc->m_out_idx - oc->m_n_member);
+ unsigned int plsize = (clsize + 2)/2;
gboolean plurality = (oc->m_n_member >= plsize);
gboolean Q = ccm_have_quorum(event);
if(clsize == 2) {
if (!Q) {
crm_err("2 nodes w/o quorum");
}
} else if(Q && !plurality) {
crm_err("Quorum w/o plurality (%d/%d nodes)",
oc->m_n_member, clsize);
} else if(plurality && !Q) {
crm_err("Plurality w/o Quorum (%d/%d nodes)",
oc->m_n_member, clsize);
} else {
crm_debug_2("Quorum(%s) and plurality (%d/%d) agree.",
Q?"true":"false", oc->m_n_member, clsize);
}
}
#endif
crm_malloc0(membership_copy, sizeof(oc_node_list_t));
if(membership_copy == NULL) {
crm_crit("Couldnt create membership copy - out of memory");
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
return I_NULL;
}
membership_copy->id = oc->m_instance;
membership_copy->last_event = event;
crm_debug_3("Copying members");
/*--*-- All Member Nodes --*--*/
offset = oc->m_memb_idx;
membership_copy->members_size = oc->m_n_member;
if(membership_copy->members_size > 0) {
membership_copy->members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->members;
for(lpc=0; lpc < membership_copy->members_size; lpc++) {
oc_node_t *member = NULL;
crm_debug_3("Copying member %d", lpc);
crm_malloc0(member, sizeof(oc_node_t));
if(member == NULL) {
continue;
}
member->node_id =
oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
member->node_uname = NULL;
if(oc->m_array[offset+lpc].node_uname != NULL) {
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
} else {
crm_err("Node %d had a NULL uname",
member->node_id);
}
g_hash_table_insert(
members, member->node_uname, member);
}
} else {
membership_copy->members = NULL;
}
crm_debug_3("Copying new members");
/*--*-- New Member Nodes --*--*/
offset = oc->m_in_idx;
membership_copy->new_members_size = oc->m_n_in;
if(membership_copy->new_members_size > 0) {
membership_copy->new_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->new_members;
for(lpc=0; lpc < membership_copy->new_members_size; lpc++) {
oc_node_t *member = NULL;
crm_malloc0(member, sizeof(oc_node_t));
if(member == NULL) {
continue;
}
member->node_uname = NULL;
member->node_id = oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
if(oc->m_array[offset+lpc].node_uname != NULL) {
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
} else {
crm_err("Node %d had a NULL uname",
member->node_id);
}
g_hash_table_insert(
members, member->node_uname, member);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->new_members = NULL;
}
crm_debug_3("Copying dead members");
/*--*-- Recently Dead Member Nodes --*--*/
offset = oc->m_out_idx;
membership_copy->dead_members_size = oc->m_n_out;
if(membership_copy->dead_members_size > 0) {
membership_copy->dead_members =
g_hash_table_new(g_str_hash, g_str_equal);
members = membership_copy->dead_members;
for(lpc=0; lpc < membership_copy->dead_members_size; lpc++) {
oc_node_t *member = NULL;
crm_malloc0(member, sizeof(oc_node_t));
if(member == NULL) {
continue;
}
member->node_id =
oc->m_array[offset+lpc].node_id;
member->node_born_on =
oc->m_array[offset+lpc].node_born_on;
member->node_uname = NULL;
CRM_DEV_ASSERT(oc->m_array[offset+lpc].node_uname != NULL);
if(oc->m_array[offset+lpc].node_uname == NULL) {
continue;
}
member->node_uname =
crm_strdup(oc->m_array[offset+lpc].node_uname);
g_hash_table_insert(
members, member->node_uname, member);
g_hash_table_insert(members, member->node_uname, member);
}
} else {
membership_copy->dead_members = NULL;
}
tmp = fsa_membership_copy;
fsa_membership_copy = membership_copy;
crm_debug_2("Updated membership cache with %d (%d new, %d lost) members",
g_hash_table_size(fsa_membership_copy->members),
g_hash_table_size(fsa_membership_copy->new_members),
g_hash_table_size(fsa_membership_copy->dead_members));
/* Free the old copy */
if(tmp != NULL) {
if(tmp->members != NULL)
g_hash_table_foreach_remove(
tmp->members, ghash_node_clfree, NULL);
if(tmp->new_members != NULL)
g_hash_table_foreach_remove(
tmp->new_members, ghash_node_clfree, NULL);
if(tmp->dead_members != NULL)
g_hash_table_foreach_remove(
tmp->dead_members, ghash_node_clfree, NULL);
crm_free(tmp);
}
crm_debug_3("Free'd old copies");
set_bit_inplace(fsa_input_register, R_CCM_DATA);
if(cur_state != S_STARTING && cur_state != S_STOPPING) {
crm_debug_3("Updating the CIB from CCM cache");
do_update_cib_nodes(NULL, FALSE);
}
return next_input;
}
void
ccm_event_detail(const oc_ev_membership_t *oc, oc_ed_t event)
{
int lpc;
gboolean member = FALSE;
member = FALSE;
crm_debug_2("-----------------------");
crm_info("%s: trans=%d, nodes=%d, new=%d, lost=%d n_idx=%d, "
"new_idx=%d, old_idx=%d",
ccm_event_name(event),
oc->m_instance,
oc->m_n_member,
oc->m_n_in,
oc->m_n_out,
oc->m_memb_idx,
oc->m_in_idx,
oc->m_out_idx);
#if !CCM_EVENT_DETAIL_PARTIAL
for(lpc=0; lpc < oc->m_n_member; lpc++) {
crm_info("\tCURRENT: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_memb_idx+lpc].node_uname,
oc->m_array[oc->m_memb_idx+lpc].node_id,
oc->m_array[oc->m_memb_idx+lpc].node_born_on);
if(safe_str_eq(fsa_our_uname,
oc->m_array[oc->m_memb_idx+lpc].node_uname)) {
member = TRUE;
}
}
if (member == FALSE) {
crm_warn("MY NODE IS NOT IN CCM THE MEMBERSHIP LIST");
}
#endif
for(lpc=0; lpc<(int)oc->m_n_in; lpc++) {
crm_info("\tNEW: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_in_idx+lpc].node_uname,
oc->m_array[oc->m_in_idx+lpc].node_id,
oc->m_array[oc->m_in_idx+lpc].node_born_on);
}
for(lpc=0; lpc<(int)oc->m_n_out; lpc++) {
crm_info("\tLOST: %s [nodeid=%d, born=%d]",
oc->m_array[oc->m_out_idx+lpc].node_uname,
oc->m_array[oc->m_out_idx+lpc].node_id,
oc->m_array[oc->m_out_idx+lpc].node_born_on);
if(fsa_our_uname != NULL
&& 0 == strcmp(fsa_our_uname,
oc->m_array[oc->m_out_idx+lpc].node_uname)) {
crm_err("We're not part of the cluster anymore");
}
}
crm_debug_2("-----------------------");
}
int
register_with_ccm(ll_cluster_t *hb_cluster)
{
return 0;
}
void
msg_ccm_join(const HA_Message *msg, void *foo)
{
crm_debug_2("###### Received ccm_join message...");
if (msg != NULL)
{
crm_debug_2("[type=%s]",
ha_msg_value(msg, F_TYPE));
crm_debug_2("[orig=%s]",
ha_msg_value(msg, F_ORIG));
crm_debug_2("[to=%s]",
ha_msg_value(msg, F_TO));
crm_debug_2("[status=%s]",
ha_msg_value(msg, F_STATUS));
crm_debug_2("[info=%s]",
ha_msg_value(msg, F_COMMENT));
crm_debug_2("[rsc_hold=%s]",
ha_msg_value(msg, F_RESOURCES));
crm_debug_2("[stable=%s]",
ha_msg_value(msg, F_ISSTABLE));
crm_debug_2("[rtype=%s]",
ha_msg_value(msg, F_RTYPE));
crm_debug_2("[ts=%s]",
ha_msg_value(msg, F_TIME));
crm_debug_2("[seq=%s]",
ha_msg_value(msg, F_SEQ));
crm_debug_2("[generation=%s]",
ha_msg_value(msg, F_HBGENERATION));
/* crm_debug_2("[=%s]", ha_msg_value(msg, F_)); */
}
return;
}
struct update_data_s
{
crm_data_t *updates;
const char *state;
const char *join;
};
crm_data_t*
do_update_cib_nodes(crm_data_t *updates, gboolean overwrite)
{
int call_options = cib_scope_local|cib_quorum_override;
struct update_data_s update_data;
crm_data_t *fragment = updates;
crm_data_t *tmp = NULL;
if(updates == NULL) {
fragment = create_cib_fragment(NULL, NULL);
crm_xml_add(fragment, XML_ATTR_SECTION, XML_CIB_TAG_STATUS);
}
tmp = find_xml_node(fragment, XML_TAG_CIB, TRUE);
tmp = get_object_root(XML_CIB_TAG_STATUS, tmp);
CRM_DEV_ASSERT(tmp != NULL);
update_data.updates = tmp;
update_data.state = XML_BOOLEAN_YES;
update_data.join = NULL;
if(overwrite) {
crm_debug_2("Performing a join update based on CCM data");
update_data.join = CRMD_JOINSTATE_PENDING;
if(fsa_membership_copy->members != NULL) {
g_hash_table_foreach(fsa_membership_copy->members,
ghash_update_cib_node, &update_data);
}
} else {
call_options = call_options|cib_inhibit_bcast;
crm_debug_2("Inhibiting bcast for CCM updates");
if(fsa_membership_copy->members != NULL) {
g_hash_table_foreach(fsa_membership_copy->new_members,
ghash_update_cib_node, &update_data);
}
update_data.state = XML_BOOLEAN_NO;
update_data.join = CRMD_JOINSTATE_DOWN;
if(fsa_membership_copy->dead_members != NULL) {
g_hash_table_foreach(fsa_membership_copy->dead_members,
ghash_update_cib_node, &update_data);
}
}
if(update_data.updates != NULL) {
fsa_cib_conn->cmds->modify(fsa_cib_conn, XML_CIB_TAG_STATUS,
fragment, NULL, call_options);
free_xml(fragment);
}
return NULL;
}
void
ghash_update_cib_node(gpointer key, gpointer value, gpointer user_data)
{
crm_data_t *tmp1 = NULL;
const char *node_uname = (const char*)key;
struct update_data_s* data = (struct update_data_s*)user_data;
crm_debug_2("%s processing %s (%s)",
__FUNCTION__, node_uname, data->state);
tmp1 = create_node_state(node_uname, node_uname,
NULL, data->state, NULL, data->join,
NULL, __FUNCTION__);
add_node_copy(data->updates, tmp1);
free_xml(tmp1);
}
gboolean
ghash_node_clfree(gpointer key, gpointer value, gpointer user_data)
{
/* value->node_uname is free'd as "key" */
if(key != NULL) {
crm_free(key);
}
if(value != NULL) {
crm_free(value);
}
return TRUE;
}
diff --git a/crm/crmd/pengine.c b/crm/crmd/pengine.c
index 9bc4c709e2..217bdd0d3e 100644
--- a/crm/crmd/pengine.c
+++ b/crm/crmd/pengine.c
@@ -1,212 +1,212 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crmd_fsa.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h> /* for access */
#include <clplumbing/cl_signal.h>
#include <clplumbing/realtime.h>
#include <clplumbing/timers.h>
#include <sys/types.h> /* for calls to open */
#include <sys/stat.h> /* for calls to open */
#include <fcntl.h> /* for calls to open */
#include <pwd.h> /* for getpwuid */
#include <grp.h> /* for initgroups */
#include <sys/time.h> /* for getrlimit */
#include <sys/resource.h>/* for getrlimit */
#include <errno.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crmd_messages.h>
#include <crmd_callbacks.h>
#include <crm/cib.h>
#include <crmd.h>
#include <crm/dmalloc_wrapper.h>
#define CLIENT_EXIT_WAIT 30
struct crm_subsystem_s *pe_subsystem = NULL;
void do_pe_invoke_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data);
/* A_PE_START, A_PE_STOP, A_TE_RESTART */
enum crmd_fsa_input
do_pe_control(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)
{
enum crmd_fsa_input result = I_NULL;
struct crm_subsystem_s *this_subsys = pe_subsystem;
long long stop_actions = A_PE_STOP;
long long start_actions = A_PE_START;
if(action & stop_actions) {
if(stop_subsystem(this_subsys) == FALSE) {
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
}
}
if(action & start_actions) {
if(cur_state != S_STOPPING) {
if(start_subsystem(this_subsys) == FALSE) {
register_fsa_error(C_FSA_INTERNAL, I_FAIL, NULL);
}
} else {
crm_info("Ignoring request to start %s while shutting down",
this_subsys->name);
}
}
return result;
}
char *fsa_pe_ref = NULL;
/* A_PE_INVOKE */
enum crmd_fsa_input
do_pe_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)
{
int call_id = 0;
if(is_set(fsa_input_register, R_PE_CONNECTED) == FALSE){
if(pe_subsystem->pid > 0) {
int pid_status = -1;
int rc = waitpid(
pe_subsystem->pid, &pid_status, WNOHANG);
if(rc > 0 && WIFEXITED(pid_status)) {
clear_bit_inplace(fsa_input_register,
pe_subsystem->flag_connected);
if(is_set(fsa_input_register,
pe_subsystem->flag_required)) {
/* this wasnt supposed to happen */
crm_err("%s[%d] terminated during start",
pe_subsystem->name,
pe_subsystem->pid);
register_fsa_error(
C_FSA_INTERNAL, I_ERROR, NULL);
}
pe_subsystem->pid = -1;
return I_NULL;
}
}
crm_info("Waiting for the PE to connect");
crmd_fsa_stall(NULL);
return I_NULL;
}
if(is_set(fsa_input_register, R_HAVE_CIB) == FALSE) {
crm_err("Attempted to invoke the PE without a consistent"
" copy of the CIB!");
/* start the join from scratch */
register_fsa_input_before(C_FSA_INTERNAL, I_ELECTION, NULL);
return I_NULL;
}
crm_debug("Requesting the current CIB");
call_id = fsa_cib_conn->cmds->query(
fsa_cib_conn, NULL, NULL, cib_scope_local);
if(FALSE == add_cib_op_callback(
call_id, TRUE, NULL, do_pe_invoke_callback)) {
crm_err("Cant retrieve the CIB to invoke the %s subsystem with",
pe_subsystem->name);
register_fsa_error(C_FSA_INTERNAL, I_ERROR, NULL);
}
return I_NULL;
}
void
do_pe_invoke_callback(const HA_Message *msg, int call_id, int rc,
crm_data_t *output, void *user_data)
{
HA_Message *cmd = NULL;
int ccm_transition_id = -1;
gboolean cib_has_quorum = FALSE;
crm_data_t *local_cib = find_xml_node(output, XML_TAG_CIB, TRUE);
if(AM_I_DC == FALSE
|| is_set(fsa_input_register, R_PE_CONNECTED) == FALSE
|| fsa_state != S_POLICY_ENGINE) {
crm_debug("No need to invoke the PE anymore");
return;
}
crm_debug_2("Invoking %s with %p", CRM_SYSTEM_PENGINE, local_cib);
CRM_DEV_ASSERT(local_cib != NULL);
CRM_DEV_ASSERT(crm_element_value(local_cib, XML_ATTR_DC_UUID) != NULL);
cib_has_quorum = crm_is_true(
crm_element_value(local_cib, XML_ATTR_HAVE_QUORUM));
ccm_transition_id = crm_atoi(
crm_element_value(local_cib, XML_ATTR_CCM_TRANSITION), "-1");
- if(ccm_transition_id < fsa_membership_copy->id) {
+ if(ccm_transition_id < (int)fsa_membership_copy->id) {
/* the cib is behind */
crm_debug("Re-asking for the CIB until membership/quorum"
" matches: CIB=%d < CRM=%d",
ccm_transition_id, fsa_membership_copy->id);
mssleep(500);
register_fsa_action(A_PE_INVOKE);
return;
- } else if(ccm_transition_id > fsa_membership_copy->id) {
+ } else if(ccm_transition_id > (int)fsa_membership_copy->id) {
/* we are behind */
crm_info("Waiting for another CCM event before proceeding:"
" CIB=%d > CRM=%d",
ccm_transition_id, fsa_membership_copy->id);
return;
}
if(fsa_pe_ref) {
crm_free(fsa_pe_ref);
fsa_pe_ref = NULL;
}
cmd = create_request(
CRM_OP_PECALC, local_cib, NULL,
CRM_SYSTEM_PENGINE, CRM_SYSTEM_DC, NULL);
send_request(cmd, &fsa_pe_ref);
crm_debug("Invoking the PE: %s", fsa_pe_ref);
}
diff --git a/crm/crmd/utils.c b/crm/crmd/utils.c
index 626238388d..f66b36ba4c 100644
--- a/crm/crmd/utils.c
+++ b/crm/crmd/utils.c
@@ -1,1381 +1,1381 @@
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crmd_fsa.h>
#include <clplumbing/Gmain_timeout.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <heartbeat.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/msg.h>
#include <crmd_messages.h>
#include <crmd_utils.h>
#include <crm/dmalloc_wrapper.h>
void copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy);
/* A_DC_TIMER_STOP, A_DC_TIMER_START,
* A_FINALIZE_TIMER_STOP, A_FINALIZE_TIMER_START
* A_INTEGRATE_TIMER_STOP, A_INTEGRATE_TIMER_START
*/
enum crmd_fsa_input
do_timer_control(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)
{
gboolean timer_op_ok = TRUE;
enum crmd_fsa_input result = I_NULL;
if(action & A_DC_TIMER_STOP) {
timer_op_ok = crm_timer_stop(election_trigger);
} else if(action & A_FINALIZE_TIMER_STOP) {
timer_op_ok = crm_timer_stop(finalization_timer);
} else if(action & A_INTEGRATE_TIMER_STOP) {
timer_op_ok = crm_timer_stop(integration_timer);
/* } else if(action & A_ELECTION_TIMEOUT_STOP) { */
/* timer_op_ok = crm_timer_stop(election_timeout); */
}
/* dont start a timer that wasnt already running */
if(action & A_DC_TIMER_START && timer_op_ok) {
crm_timer_start(election_trigger);
if(AM_I_DC) {
/* there can be only one */
result = I_ELECTION;
}
} else if(action & A_FINALIZE_TIMER_START) {
crm_timer_start(finalization_timer);
} else if(action & A_INTEGRATE_TIMER_START) {
crm_timer_start(integration_timer);
/* } else if(action & A_ELECTION_TIMEOUT_START) { */
/* crm_timer_start(election_timeout); */
}
return I_NULL;
}
gboolean
crm_timer_popped(gpointer data)
{
fsa_timer_t *timer = (fsa_timer_t *)data;
if(timer == election_trigger) {
crm_info("Election Trigger (%s) just popped!",
fsa_input2string(timer->fsa_input));
} else if(timer == election_timeout) {
crm_info("Election Timeout (%s) just popped!",
fsa_input2string(timer->fsa_input));
} else {
crm_info("Timer %s just popped!",
fsa_input2string(timer->fsa_input));
}
if(timer->repeat == FALSE) {
crm_timer_stop(timer); /* make it _not_ go off again */
}
if(timer->fsa_input == I_INTEGRATED) {
register_fsa_input_before(
C_TIMER_POPPED, timer->fsa_input, NULL);
} else if(timer->fsa_input == I_FINALIZED
&& fsa_state != S_FINALIZE_JOIN) {
crm_debug("Discarding I_FINALIZED event in state: %s",
fsa_state2string(fsa_state));
} else if(timer->fsa_input != I_NULL) {
register_fsa_input(C_TIMER_POPPED, timer->fsa_input, NULL);
}
G_main_set_trigger(fsa_source);
return TRUE;
}
gboolean
crm_timer_start(fsa_timer_t *timer)
{
const char *timer_desc = NULL;
if(timer == election_trigger) {
timer_desc = "Election Trigger";
} else if(timer == election_timeout) {
timer_desc = "Election Timeout";
} else {
timer_desc = "Timer";
}
if((timer->source_id == (guint)-1 || timer->source_id == (guint)-2)
&& timer->period_ms > 0) {
timer->source_id = Gmain_timeout_add(
timer->period_ms, timer->callback, (void*)timer);
crm_debug("Started %s (%s:%dms), src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
} else if(timer->period_ms < 0) {
crm_err("Tried to start %s (%s:%dms) with a -ve period",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms);
} else {
crm_debug("%s (%s:%dms) already running: src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
return FALSE;
}
return TRUE;
}
gboolean
crm_timer_stop(fsa_timer_t *timer)
{
const char *timer_desc = NULL;
if(timer == election_trigger) {
timer_desc = "Election Trigger";
} else if(timer == election_timeout) {
timer_desc = "Election Timeout";
} else if(timer == wait_timer) {
timer_desc = "Stall Timeout";
} else {
timer_desc = "Timer";
}
if(timer == NULL) {
crm_err("Attempted to stop NULL timer");
return FALSE;
} else if(timer->source_id != (guint)-1
&& timer->source_id != (guint)-2) {
crm_debug("Stopping %s (%s:%dms), src=%d",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms, timer->source_id);
g_source_remove(timer->source_id);
timer->source_id = -2;
} else {
crm_debug_2("%s (%s:%dms) already stopped",
timer_desc, fsa_input2string(timer->fsa_input),
timer->period_ms);
timer->source_id = -2;
return FALSE;
}
return TRUE;
}
long long
toggle_bit(long long action_list, long long action)
{
crm_debug_5("Toggling bit %.16llx", action);
action_list ^= action;
crm_debug_5("Result %.16llx", action_list & action);
return action_list;
}
long long
clear_bit(long long action_list, long long action)
{
- int level = LOG_DEBUG_5;
+ unsigned int level = LOG_DEBUG_5;
crm_log_maybe(level, "Clearing bit\t%.16llx", action);
/* ensure its set */
action_list |= action;
/* then toggle */
action_list = action_list ^ action;
return action_list;
}
long long
set_bit(long long action_list, long long action)
{
- int level = LOG_DEBUG_5;
+ unsigned int level = LOG_DEBUG_5;
crm_log_maybe(level, "Setting bit\t%.16llx", action);
action_list |= action;
return action_list;
}
gboolean
is_set(long long action_list, long long action)
{
crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
return ((action_list & action) == action);
}
gboolean
is_set_any(long long action_list, long long action)
{
crm_debug_5("Checking bit\t%.16llx in %.16llx", action, action_list);
return ((action_list & action) != 0);
}
const char *
fsa_input2string(enum crmd_fsa_input input)
{
const char *inputAsText = NULL;
switch(input){
case I_NULL:
inputAsText = "I_NULL";
break;
case I_CCM_EVENT:
inputAsText = "I_CCM_EVENT";
break;
case I_CIB_OP:
inputAsText = "I_CIB_OP";
break;
case I_CIB_UPDATE:
inputAsText = "I_CIB_UPDATE";
break;
case I_DC_TIMEOUT:
inputAsText = "I_DC_TIMEOUT";
break;
case I_ELECTION:
inputAsText = "I_ELECTION";
break;
case I_PE_CALC:
inputAsText = "I_PE_CALC";
break;
case I_RELEASE_DC:
inputAsText = "I_RELEASE_DC";
break;
case I_ELECTION_DC:
inputAsText = "I_ELECTION_DC";
break;
case I_ERROR:
inputAsText = "I_ERROR";
break;
case I_FAIL:
inputAsText = "I_FAIL";
break;
case I_INTEGRATED:
inputAsText = "I_INTEGRATED";
break;
case I_FINALIZED:
inputAsText = "I_FINALIZED";
break;
case I_NODE_JOIN:
inputAsText = "I_NODE_JOIN";
break;
case I_JOIN_OFFER:
inputAsText = "I_JOIN_OFFER";
break;
case I_JOIN_REQUEST:
inputAsText = "I_JOIN_REQUEST";
break;
case I_JOIN_RESULT:
inputAsText = "I_JOIN_RESULT";
break;
case I_NOT_DC:
inputAsText = "I_NOT_DC";
break;
case I_RECOVERED:
inputAsText = "I_RECOVERED";
break;
case I_RELEASE_FAIL:
inputAsText = "I_RELEASE_FAIL";
break;
case I_RELEASE_SUCCESS:
inputAsText = "I_RELEASE_SUCCESS";
break;
case I_RESTART:
inputAsText = "I_RESTART";
break;
case I_PE_SUCCESS:
inputAsText = "I_PE_SUCCESS";
break;
case I_ROUTER:
inputAsText = "I_ROUTER";
break;
case I_SHUTDOWN:
inputAsText = "I_SHUTDOWN";
break;
case I_STARTUP:
inputAsText = "I_STARTUP";
break;
case I_TE_SUCCESS:
inputAsText = "I_TE_SUCCESS";
break;
case I_STOP:
inputAsText = "I_STOP";
break;
case I_DC_HEARTBEAT:
inputAsText = "I_DC_HEARTBEAT";
break;
case I_WAIT_FOR_EVENT:
inputAsText = "I_WAIT_FOR_EVENT";
break;
case I_LRM_EVENT:
inputAsText = "I_LRM_EVENT";
break;
case I_PENDING:
inputAsText = "I_PENDING";
break;
case I_HALT:
inputAsText = "I_HALT";
break;
case I_TERMINATE:
inputAsText = "I_TERMINATE";
break;
case I_ILLEGAL:
inputAsText = "I_ILLEGAL";
break;
}
if(inputAsText == NULL) {
crm_err("Input %d is unknown", input);
inputAsText = "<UNKNOWN_INPUT>";
}
return inputAsText;
}
const char *
fsa_state2string(enum crmd_fsa_state state)
{
const char *stateAsText = NULL;
switch(state){
case S_IDLE:
stateAsText = "S_IDLE";
break;
case S_ELECTION:
stateAsText = "S_ELECTION";
break;
case S_INTEGRATION:
stateAsText = "S_INTEGRATION";
break;
case S_FINALIZE_JOIN:
stateAsText = "S_FINALIZE_JOIN";
break;
case S_NOT_DC:
stateAsText = "S_NOT_DC";
break;
case S_POLICY_ENGINE:
stateAsText = "S_POLICY_ENGINE";
break;
case S_RECOVERY:
stateAsText = "S_RECOVERY";
break;
case S_RELEASE_DC:
stateAsText = "S_RELEASE_DC";
break;
case S_PENDING:
stateAsText = "S_PENDING";
break;
case S_STOPPING:
stateAsText = "S_STOPPING";
break;
case S_TERMINATE:
stateAsText = "S_TERMINATE";
break;
case S_TRANSITION_ENGINE:
stateAsText = "S_TRANSITION_ENGINE";
break;
case S_STARTING:
stateAsText = "S_STARTING";
break;
case S_HALT:
stateAsText = "S_HALT";
break;
case S_ILLEGAL:
stateAsText = "S_ILLEGAL";
break;
}
if(stateAsText == NULL) {
crm_err("State %d is unknown", state);
stateAsText = "<UNKNOWN_STATE>";
}
return stateAsText;
}
const char *
fsa_cause2string(enum crmd_fsa_cause cause)
{
const char *causeAsText = NULL;
switch(cause){
case C_UNKNOWN:
causeAsText = "C_UNKNOWN";
break;
case C_STARTUP:
causeAsText = "C_STARTUP";
break;
case C_IPC_MESSAGE:
causeAsText = "C_IPC_MESSAGE";
break;
case C_HA_MESSAGE:
causeAsText = "C_HA_MESSAGE";
break;
case C_CCM_CALLBACK:
causeAsText = "C_CCM_CALLBACK";
break;
case C_TIMER_POPPED:
causeAsText = "C_TIMER_POPPED";
break;
case C_SHUTDOWN:
causeAsText = "C_SHUTDOWN";
break;
case C_HEARTBEAT_FAILED:
causeAsText = "C_HEARTBEAT_FAILED";
break;
case C_SUBSYSTEM_CONNECT:
causeAsText = "C_SUBSYSTEM_CONNECT";
break;
case C_LRM_OP_CALLBACK:
causeAsText = "C_LRM_OP_CALLBACK";
break;
case C_LRM_MONITOR_CALLBACK:
causeAsText = "C_LRM_MONITOR_CALLBACK";
break;
case C_CRMD_STATUS_CALLBACK:
causeAsText = "C_CRMD_STATUS_CALLBACK";
break;
case C_HA_DISCONNECT:
causeAsText = "C_HA_DISCONNECT";
break;
case C_FSA_INTERNAL:
causeAsText = "C_FSA_INTERNAL";
break;
case C_ILLEGAL:
causeAsText = "C_ILLEGAL";
break;
}
if(causeAsText == NULL) {
crm_err("Cause %d is unknown", cause);
causeAsText = "<UNKNOWN_CAUSE>";
}
return causeAsText;
}
const char *
fsa_action2string(long long action)
{
const char *actionAsText = NULL;
switch(action){
case A_NOTHING:
actionAsText = "A_NOTHING";
break;
case A_ELECTION_START:
actionAsText = "A_ELECTION_START";
break;
case A_READCONFIG:
actionAsText = "A_READCONFIG";
break;
case O_RELEASE:
actionAsText = "O_RELEASE";
break;
case A_STARTUP:
actionAsText = "A_STARTUP";
break;
case A_STARTED:
actionAsText = "A_STARTED";
break;
case A_HA_CONNECT:
actionAsText = "A_HA_CONNECT";
break;
case A_HA_DISCONNECT:
actionAsText = "A_HA_DISCONNECT";
break;
case A_LRM_CONNECT:
actionAsText = "A_LRM_CONNECT";
break;
case A_LRM_EVENT:
actionAsText = "A_LRM_EVENT";
break;
case A_LRM_INVOKE:
actionAsText = "A_LRM_INVOKE";
break;
case A_LRM_DISCONNECT:
actionAsText = "A_LRM_DISCONNECT";
break;
case A_CL_JOIN_QUERY:
actionAsText = "A_CL_JOIN_QUERY";
break;
case A_DC_TIMER_STOP:
actionAsText = "A_DC_TIMER_STOP";
break;
case A_DC_TIMER_START:
actionAsText = "A_DC_TIMER_START";
break;
case A_INTEGRATE_TIMER_START:
actionAsText = "A_INTEGRATE_TIMER_START";
break;
case A_INTEGRATE_TIMER_STOP:
actionAsText = "A_INTEGRATE_TIMER_STOP";
break;
case A_FINALIZE_TIMER_START:
actionAsText = "A_FINALIZE_TIMER_START";
break;
case A_FINALIZE_TIMER_STOP:
actionAsText = "A_FINALIZE_TIMER_STOP";
break;
case A_ELECTION_COUNT:
actionAsText = "A_ELECTION_COUNT";
break;
case A_ELECTION_VOTE:
actionAsText = "A_ELECTION_VOTE";
break;
case A_CL_JOIN_ANNOUNCE:
actionAsText = "A_CL_JOIN_ANNOUNCE";
break;
case A_CL_JOIN_REQUEST:
actionAsText = "A_CL_JOIN_REQUEST";
break;
case A_CL_JOIN_RESULT:
actionAsText = "A_CL_JOIN_RESULT";
break;
case A_DC_JOIN_OFFER_ALL:
actionAsText = "A_DC_JOIN_OFFER_ALL";
break;
case A_DC_JOIN_OFFER_ONE:
actionAsText = "A_DC_JOIN_OFFER_ONE";
break;
case A_DC_JOIN_PROCESS_REQ:
actionAsText = "A_DC_JOIN_PROCESS_REQ";
break;
case A_DC_JOIN_PROCESS_ACK:
actionAsText = "A_DC_JOIN_PROCESS_ACK";
break;
case A_DC_JOIN_FINALIZE:
actionAsText = "A_DC_JOIN_FINALIZE";
break;
case A_MSG_PROCESS:
actionAsText = "A_MSG_PROCESS";
break;
case A_MSG_ROUTE:
actionAsText = "A_MSG_ROUTE";
break;
case A_RECOVER:
actionAsText = "A_RECOVER";
break;
case A_DC_RELEASE:
actionAsText = "A_DC_RELEASE";
break;
case A_DC_RELEASED:
actionAsText = "A_DC_RELEASED";
break;
case A_DC_TAKEOVER:
actionAsText = "A_DC_TAKEOVER";
break;
case A_SHUTDOWN:
actionAsText = "A_SHUTDOWN";
break;
case A_SHUTDOWN_REQ:
actionAsText = "A_SHUTDOWN_REQ";
break;
case A_STOP:
actionAsText = "A_STOP ";
break;
case A_EXIT_0:
actionAsText = "A_EXIT_0";
break;
case A_EXIT_1:
actionAsText = "A_EXIT_1";
break;
case A_CCM_CONNECT:
actionAsText = "A_CCM_CONNECT";
break;
case A_CCM_DISCONNECT:
actionAsText = "A_CCM_DISCONNECT";
break;
case A_CCM_EVENT:
actionAsText = "A_CCM_EVENT";
break;
case A_CCM_UPDATE_CACHE:
actionAsText = "A_CCM_UPDATE_CACHE";
break;
case A_CIB_BUMPGEN:
actionAsText = "A_CIB_BUMPGEN";
break;
case A_CIB_INVOKE:
actionAsText = "A_CIB_INVOKE";
break;
case O_CIB_RESTART:
actionAsText = "O_CIB_RESTART";
break;
case A_CIB_START:
actionAsText = "A_CIB_START";
break;
case A_CIB_STOP:
actionAsText = "A_CIB_STOP";
break;
case A_TE_INVOKE:
actionAsText = "A_TE_INVOKE";
break;
case O_TE_RESTART:
actionAsText = "O_TE_RESTART";
break;
case A_TE_START:
actionAsText = "A_TE_START";
break;
case A_TE_STOP:
actionAsText = "A_TE_STOP";
break;
case A_TE_CANCEL:
actionAsText = "A_TE_CANCEL";
break;
case A_PE_INVOKE:
actionAsText = "A_PE_INVOKE";
break;
case O_PE_RESTART:
actionAsText = "O_PE_RESTART";
break;
case A_PE_START:
actionAsText = "A_PE_START";
break;
case A_PE_STOP:
actionAsText = "A_PE_STOP";
break;
case A_NODE_BLOCK:
actionAsText = "A_NODE_BLOCK";
break;
case A_UPDATE_NODESTATUS:
actionAsText = "A_UPDATE_NODESTATUS";
break;
case A_LOG:
actionAsText = "A_LOG ";
break;
case A_ERROR:
actionAsText = "A_ERROR ";
break;
case A_WARN:
actionAsText = "A_WARN ";
break;
}
if(actionAsText == NULL) {
crm_err("Action %.16llx is unknown", action);
actionAsText = "<UNKNOWN_ACTION>";
}
return actionAsText;
}
void
fsa_dump_inputs(int log_level, const char *text, long long input_register)
{
if(input_register == A_NOTHING) {
return;
}
if(text == NULL) {
text = "Input register contents:";
}
if(is_set(input_register, R_THE_DC)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_THE_DC)", text, R_THE_DC);
}
if(is_set(input_register, R_STARTING)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_STARTING)", text, R_STARTING);
}
if(is_set(input_register, R_SHUTDOWN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_SHUTDOWN)", text, R_SHUTDOWN);
}
if(is_set(input_register, R_STAYDOWN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_STAYDOWN)", text, R_STAYDOWN);
}
if(is_set(input_register, R_JOIN_OK)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_JOIN_OK)", text, R_JOIN_OK);
}
if(is_set(input_register, R_HAVE_RES)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_HAVE_RES)", text, R_HAVE_RES);
}
if(is_set(input_register, R_INVOKE_PE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_INVOKE_PE)", text, R_INVOKE_PE);
}
if(is_set(input_register, R_CIB_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_CONNECTED)", text, R_CIB_CONNECTED);
}
if(is_set(input_register, R_PE_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PE_CONNECTED)", text, R_PE_CONNECTED);
}
if(is_set(input_register, R_TE_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_TE_CONNECTED)", text, R_TE_CONNECTED);
}
if(is_set(input_register, R_LRM_CONNECTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_LRM_CONNECTED)", text, R_LRM_CONNECTED);
}
if(is_set(input_register, R_CIB_REQUIRED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_REQUIRED)", text, R_CIB_REQUIRED);
}
if(is_set(input_register, R_PE_REQUIRED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PE_REQUIRED)", text, R_PE_REQUIRED);
}
if(is_set(input_register, R_TE_REQUIRED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_TE_REQUIRED)", text, R_TE_REQUIRED);
}
if(is_set(input_register, R_REQ_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_REQ_PEND)", text, R_REQ_PEND);
}
if(is_set(input_register, R_PE_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PE_PEND)", text, R_PE_PEND);
}
if(is_set(input_register, R_TE_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_TE_PEND)", text, R_TE_PEND);
}
if(is_set(input_register, R_RESP_PEND)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_RESP_PEND)", text, R_RESP_PEND);
}
if(is_set(input_register, R_CIB_DONE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_DONE)", text, R_CIB_DONE);
}
if(is_set(input_register, R_HAVE_CIB)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_HAVE_CIB)", text, R_HAVE_CIB);
}
if(is_set(input_register, R_CIB_ASKED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CIB_ASKED)", text, R_CIB_ASKED);
}
if(is_set(input_register, R_CCM_DATA)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_CCM_DATA)", text, R_CCM_DATA);
}
if(is_set(input_register, R_PEER_DATA)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_PEER_DATA)", text, R_PEER_DATA);
}
if(is_set(input_register, R_IN_RECOVERY)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s %.16llx (R_IN_RECOVERY)", text, R_IN_RECOVERY);
}
}
void
fsa_dump_actions(long long action, const char *text)
{
int log_level = LOG_DEBUG_3;
if(is_set(action, A_READCONFIG)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_READCONFIG) %s", A_READCONFIG, text);
}
if(is_set(action, A_STARTUP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_STARTUP) %s", A_STARTUP, text);
}
if(is_set(action, A_STARTED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_STARTED) %s", A_STARTED, text);
}
if(is_set(action, A_HA_CONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CONNECT) %s", A_HA_CONNECT, text);
}
if(is_set(action, A_HA_DISCONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DISCONNECT) %s",
A_HA_DISCONNECT, text);
}
if(is_set(action, A_LRM_CONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_CONNECT) %s",
A_LRM_CONNECT, text);
}
if(is_set(action, A_LRM_EVENT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_EVENT) %s",
A_LRM_EVENT, text);
}
if(is_set(action, A_LRM_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_INVOKE) %s",
A_LRM_INVOKE, text);
}
if(is_set(action, A_LRM_DISCONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LRM_DISCONNECT) %s",
A_LRM_DISCONNECT, text);
}
if(is_set(action, A_DC_TIMER_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_TIMER_STOP) %s",
A_DC_TIMER_STOP, text);
}
if(is_set(action, A_DC_TIMER_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_TIMER_START) %s",
A_DC_TIMER_START, text);
}
if(is_set(action, A_INTEGRATE_TIMER_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_INTEGRATE_TIMER_START) %s",
A_INTEGRATE_TIMER_START, text);
}
if(is_set(action, A_INTEGRATE_TIMER_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_INTEGRATE_TIMER_STOP) %s",
A_INTEGRATE_TIMER_STOP, text);
}
if(is_set(action, A_FINALIZE_TIMER_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_FINALIZE_TIMER_START) %s",
A_FINALIZE_TIMER_START, text);
}
if(is_set(action, A_FINALIZE_TIMER_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_FINALIZE_TIMER_STOP) %s",
A_FINALIZE_TIMER_STOP, text);
}
if(is_set(action, A_ELECTION_COUNT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_ELECTION_COUNT) %s",
A_ELECTION_COUNT, text);
}
if(is_set(action, A_ELECTION_VOTE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_ELECTION_VOTE) %s",
A_ELECTION_VOTE, text);
}
if(is_set(action, A_CL_JOIN_ANNOUNCE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CL_JOIN_ANNOUNCE) %s",
A_CL_JOIN_ANNOUNCE, text);
}
if(is_set(action, A_CL_JOIN_REQUEST)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CL_JOIN_REQUEST) %s",
A_CL_JOIN_REQUEST, text);
}
if(is_set(action, A_CL_JOIN_RESULT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CL_JOIN_RESULT) %s",
A_CL_JOIN_RESULT, text);
}
if(is_set(action, A_DC_JOIN_OFFER_ALL)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_OFFER_ALL) %s",
A_DC_JOIN_OFFER_ALL, text);
}
if(is_set(action, A_DC_JOIN_OFFER_ONE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_OFFER_ONE) %s",
A_DC_JOIN_OFFER_ONE, text);
}
if(is_set(action, A_DC_JOIN_PROCESS_REQ)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_PROCESS_REQ) %s",
A_DC_JOIN_PROCESS_REQ, text);
}
if(is_set(action, A_DC_JOIN_PROCESS_ACK)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_PROCESS_ACK) %s",
A_DC_JOIN_PROCESS_ACK, text);
}
if(is_set(action, A_DC_JOIN_FINALIZE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_JOIN_FINALIZE) %s",
A_DC_JOIN_FINALIZE, text);
}
if(is_set(action, A_MSG_PROCESS)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_MSG_PROCESS) %s",
A_MSG_PROCESS, text);
}
if(is_set(action, A_MSG_ROUTE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_MSG_ROUTE) %s",
A_MSG_ROUTE, text);
}
if(is_set(action, A_RECOVER)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_RECOVER) %s",
A_RECOVER, text);
}
if(is_set(action, A_DC_RELEASE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_RELEASE) %s",
A_DC_RELEASE, text);
}
if(is_set(action, A_DC_RELEASED)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_RELEASED) %s",
A_DC_RELEASED, text);
}
if(is_set(action, A_DC_TAKEOVER)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_DC_TAKEOVER) %s",
A_DC_TAKEOVER, text);
}
if(is_set(action, A_SHUTDOWN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_SHUTDOWN) %s", A_SHUTDOWN, text);
}
if(is_set(action, A_SHUTDOWN_REQ)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_SHUTDOWN_REQ) %s",
A_SHUTDOWN_REQ, text);
}
if(is_set(action, A_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_STOP ) %s", A_STOP , text);
}
if(is_set(action, A_EXIT_0)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_EXIT_0) %s", A_EXIT_0, text);
}
if(is_set(action, A_EXIT_1)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_EXIT_1) %s", A_EXIT_1, text);
}
if(is_set(action, A_CCM_CONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_CONNECT) %s",
A_CCM_CONNECT, text);
}
if(is_set(action, A_CCM_DISCONNECT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_DISCONNECT) %s",
A_CCM_DISCONNECT, text);
}
if(is_set(action, A_CCM_EVENT)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_EVENT) %s",
A_CCM_EVENT, text);
}
if(is_set(action, A_CCM_UPDATE_CACHE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CCM_UPDATE_CACHE) %s",
A_CCM_UPDATE_CACHE, text);
}
if(is_set(action, A_CIB_BUMPGEN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_BUMPGEN) %s",
A_CIB_BUMPGEN, text);
}
if(is_set(action, A_CIB_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_INVOKE) %s",
A_CIB_INVOKE, text);
}
if(is_set(action, A_CIB_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_START) %s",
A_CIB_START, text);
}
if(is_set(action, A_CIB_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_CIB_STOP) %s", A_CIB_STOP, text);
}
if(is_set(action, A_TE_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_INVOKE) %s", A_TE_INVOKE, text);
}
if(is_set(action, A_TE_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_START) %s",
A_TE_START, text);
}
if(is_set(action, A_TE_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_STOP) %s", A_TE_STOP, text);
}
if(is_set(action, A_TE_CANCEL)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_TE_CANCEL) %s",
A_TE_CANCEL, text);
}
if(is_set(action, A_PE_INVOKE)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_PE_INVOKE) %s",
A_PE_INVOKE, text);
}
if(is_set(action, A_PE_START)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_PE_START) %s", A_PE_START, text);
}
if(is_set(action, A_PE_STOP)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_PE_STOP) %s", A_PE_STOP, text);
}
if(is_set(action, A_NODE_BLOCK)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_NODE_BLOCK) %s",
A_NODE_BLOCK, text);
}
if(is_set(action, A_UPDATE_NODESTATUS)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_UPDATE_NODESTATUS) %s",
A_UPDATE_NODESTATUS, text);
}
if(is_set(action, A_LOG)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_LOG ) %s", A_LOG, text);
}
if(is_set(action, A_ERROR)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_ERROR ) %s", A_ERROR, text);
}
if(is_set(action, A_WARN)) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"Action %.16llx (A_WARN ) %s", A_WARN, text);
}
}
void
create_node_entry(const char *uuid, const char *uname, const char *type)
{
/* 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.
*/
crm_data_t *tmp1 = create_xml_node(NULL, XML_CIB_TAG_NODE);
crm_debug_3("Creating node entry for %s", uname);
set_uuid(fsa_cluster_conn, tmp1, XML_ATTR_UUID, uname);
crm_xml_add(tmp1, XML_ATTR_UNAME, uname);
crm_xml_add(tmp1, XML_ATTR_TYPE, type);
update_local_cib(create_cib_fragment(tmp1, NULL));
free_xml(tmp1);
}
struct crmd_ccm_data_s *
copy_ccm_data(const struct crmd_ccm_data_s *ccm_input)
{
const oc_ev_membership_t *oc_in =
(const oc_ev_membership_t *)ccm_input->oc;
struct crmd_ccm_data_s *ccm_input_copy = NULL;
crm_malloc0(ccm_input_copy, sizeof(struct crmd_ccm_data_s));
ccm_input_copy->oc = copy_ccm_oc_data(oc_in);
ccm_input_copy->event = ccm_input->event;
return ccm_input_copy;
}
oc_ev_membership_t *
copy_ccm_oc_data(const oc_ev_membership_t *oc_in)
{
unsigned lpc = 0;
int size = 0;
int offset = 0;
unsigned num_nodes = 0;
oc_ev_membership_t *oc_copy = NULL;
if(oc_in->m_n_member > 0
&& num_nodes < oc_in->m_n_member + oc_in->m_memb_idx) {
num_nodes = oc_in->m_n_member + oc_in->m_memb_idx;
crm_debug_3("Updated ccm nodes to %d - 1", num_nodes);
}
if(oc_in->m_n_in > 0
&& num_nodes < oc_in->m_n_in + oc_in->m_in_idx) {
num_nodes = oc_in->m_n_in + oc_in->m_in_idx;
crm_debug_3("Updated ccm nodes to %d - 2", num_nodes);
}
if(oc_in->m_n_out > 0
&& num_nodes < oc_in->m_n_out + oc_in->m_out_idx) {
num_nodes = oc_in->m_n_out + oc_in->m_out_idx;
crm_debug_3("Updated ccm nodes to %d - 3", num_nodes);
}
/* why 2*??
* ccm code does it like this so i guess its right...
*/
size = sizeof(oc_ev_membership_t)
+ sizeof(int)
+ 2*num_nodes*sizeof(oc_node_t);
crm_debug_3("Copying %d ccm nodes", num_nodes);
crm_malloc0(oc_copy, size);
oc_copy->m_instance = oc_in->m_instance;
oc_copy->m_n_member = oc_in->m_n_member;
oc_copy->m_memb_idx = oc_in->m_memb_idx;
oc_copy->m_n_out = oc_in->m_n_out;
oc_copy->m_out_idx = oc_in->m_out_idx;
oc_copy->m_n_in = oc_in->m_n_in;
oc_copy->m_in_idx = oc_in->m_in_idx;
crm_debug_3("instance=%d, nodes=%d (idx=%d), new=%d (idx=%d), lost=%d (idx=%d)",
oc_in->m_instance,
oc_in->m_n_member,
oc_in->m_memb_idx,
oc_in->m_n_in,
oc_in->m_in_idx,
oc_in->m_n_out,
oc_in->m_out_idx);
offset = oc_in->m_memb_idx;
for(lpc = 0; lpc < oc_in->m_n_member; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm member node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
offset = oc_in->m_in_idx;
for(lpc = 0; lpc < oc_in->m_n_in; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm new node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
offset = oc_in->m_out_idx;
for(lpc = 0; lpc < oc_in->m_n_out; lpc++) {
oc_node_t a_node = oc_in->m_array[lpc+offset];
oc_node_t *a_node_copy = &(oc_copy->m_array[lpc+offset]);
crm_debug_3("Copying ccm lost node %d", lpc);
copy_ccm_node(a_node, a_node_copy);
}
return oc_copy;
}
void
copy_ccm_node(oc_node_t a_node, oc_node_t *a_node_copy)
{
crm_debug_3("Copying ccm node: id=%d, born=%d, uname=%s",
a_node.node_id, a_node.node_born_on,
a_node.node_uname);
a_node_copy->node_id = a_node.node_id;
a_node_copy->node_born_on = a_node.node_born_on;
a_node_copy->node_uname = NULL;
if(a_node.node_uname != NULL) {
a_node_copy->node_uname =
crm_strdup(a_node.node_uname);
} else {
crm_err("Node Id %d had a NULL uname!",
a_node.node_id);
}
crm_debug_3("Copied ccm node: id=%d, born=%d, uname=%s",
a_node_copy->node_id, a_node_copy->node_born_on,
a_node_copy->node_uname);
}
lrm_op_t *
copy_lrm_op(const lrm_op_t *op)
{
lrm_op_t *op_copy = NULL;
crm_malloc0(op_copy, sizeof(lrm_op_t));
op_copy->op_type = crm_strdup(op->op_type);
/* input fields */
/* GHashTable* params; */
op_copy->params = NULL;
op_copy->timeout = op->timeout;
op_copy->interval = op->interval;
op_copy->target_rc = op->target_rc;
/* in the CRM, this is always an int */
if(op->user_data != NULL) {
op_copy->user_data = crm_strdup(op->user_data);
}
/* output fields */
op_copy->op_status = op->op_status;
op_copy->rc = op->rc;
op_copy->call_id = op->call_id;
op_copy->output = NULL;
op_copy->rsc_id = crm_strdup(op->rsc_id);
op_copy->app_name = crm_strdup(op->app_name);
if(op->output!= NULL) {
op_copy->output = crm_strdup(op->output);
}
return op_copy;
}
lrm_rsc_t *
copy_lrm_rsc(const lrm_rsc_t *rsc)
{
lrm_rsc_t *rsc_copy = NULL;
if(rsc == NULL) {
return NULL;
}
crm_malloc0(rsc_copy, sizeof(lrm_rsc_t));
rsc_copy->id = crm_strdup(rsc->id);
rsc_copy->type = crm_strdup(rsc->type);
rsc_copy->class = NULL;
rsc_copy->provider = NULL;
if(rsc->class != NULL) {
rsc_copy->class = crm_strdup(rsc->class);
}
if(rsc->provider != NULL) {
rsc_copy->provider = crm_strdup(rsc->provider);
}
/* GHashTable* params; */
rsc_copy->params = NULL;
rsc_copy->ops = NULL;
return rsc_copy;
}
crm_data_t*
create_node_state(
const char *uuid, const char *uname,
const char *ha_state, const char *ccm_state,
const char *crmd_state, const char *join_state, const char *exp_state,
const char *src)
{
crm_data_t *node_state = create_xml_node(NULL, XML_CIB_TAG_STATE);
crm_debug_2("%s Creating node state entry for %s", src, uname);
set_uuid(fsa_cluster_conn, node_state, XML_ATTR_UUID, uname);
crm_xml_add(node_state, XML_ATTR_UNAME, uname);
crm_xml_add(node_state, XML_CIB_ATTR_HASTATE, ha_state);
crm_xml_add(node_state, XML_CIB_ATTR_INCCM, ccm_state);
crm_xml_add(node_state, XML_CIB_ATTR_CRMDSTATE, crmd_state);
crm_xml_add(node_state, XML_CIB_ATTR_JOINSTATE, join_state);
crm_xml_add(node_state, XML_CIB_ATTR_EXPSTATE, exp_state);
crm_xml_add(node_state, "origin", src);
crm_log_xml_debug_3(node_state, "created");
return node_state;
}
gboolean
need_transition(enum crmd_fsa_state state)
{
if(state == S_POLICY_ENGINE
|| state == S_TRANSITION_ENGINE
|| state == S_IDLE) {
return TRUE;
}
return FALSE;
}
extern GHashTable *ipc_clients;
void
process_client_disconnect(crmd_client_t *curr_client)
{
struct crm_subsystem_s *the_subsystem = NULL;
CRM_DEV_ASSERT(curr_client != NULL);
if(crm_assert_failed) { return; }
crm_debug_2("received HUP from %s", curr_client->table_key);
if (curr_client->sub_sys == NULL) {
crm_debug("Client hadn't registered with us yet");
} else if (strcmp(CRM_SYSTEM_PENGINE, curr_client->sub_sys) == 0) {
the_subsystem = pe_subsystem;
} else if (strcmp(CRM_SYSTEM_TENGINE, curr_client->sub_sys) == 0) {
the_subsystem = te_subsystem;
} else if (strcmp(CRM_SYSTEM_CIB, curr_client->sub_sys) == 0){
the_subsystem = cib_subsystem;
}
if(the_subsystem != NULL) {
the_subsystem->ipc = NULL;
} /* else that was a transient client */
if (curr_client->table_key != NULL) {
/*
* Key is destroyed below:
* curr_client->table_key
* Value is cleaned up by:
* G_main_del_IPC_Channel
*/
g_hash_table_remove(ipc_clients, curr_client->table_key);
}
crm_free(curr_client->table_key);
crm_free(curr_client->sub_sys);
crm_free(curr_client->uuid);
crm_free(curr_client);
}
diff --git a/crm/pengine/pe_utils.h b/crm/pengine/pe_utils.h
index 3e45f49b48..ee04868e1e 100644
--- a/crm/pengine/pe_utils.h
+++ b/crm/pengine/pe_utils.h
@@ -1,151 +1,151 @@
-/* $Id: pe_utils.h,v 1.27 2005/06/16 12:36:20 andrew Exp $ */
+/* $Id: pe_utils.h,v 1.28 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#ifndef PE_UTILS__H
#define PE_UTILS__H
/* General utilities */
extern resource_t *pe_find_resource(GListPtr rsc_list, const char *id_rh);
extern float merge_weights(float w1, float w2);
/* Constraint helper functions */
extern rsc_colocation_t *invert_constraint(rsc_colocation_t *constraint);
extern rsc_to_node_t *copy_constraint(rsc_to_node_t *constraint);
/* Color helper functions */
extern void add_color_to_rsc(resource_t *rsc, color_t *color);
extern color_t *find_color(GListPtr candidate_colors, color_t *other_color);
extern color_t *create_color(
pe_working_set_t *data_set, resource_t *resource, GListPtr resources);
extern color_t *copy_color(color_t *a_color);
/* Node helper functions */
extern node_t *pe_find_node(GListPtr node_list, const char *uname);
extern node_t *pe_find_node_id(GListPtr node_list, const char *id);
extern node_t *node_copy(node_t *this_node) ;
/* Binary like operators for lists of nodes */
extern GListPtr node_list_dup(GListPtr list1, gboolean filter);
extern GListPtr node_list_and(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_xor(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_minus(GListPtr list1,GListPtr list2,gboolean filter);
extern gboolean node_list_eq(GListPtr list1, GListPtr list2, gboolean filter);
extern GListPtr node_list_or(GListPtr list1, GListPtr list2, gboolean filter);
/* For creating the transition graph */
extern crm_data_t *action2xml(action_t *action, gboolean as_input);
/* Printing functions for debug */
extern void print_node(
const char *pre_text, node_t *node, gboolean details);
extern void print_resource(
const char *pre_text, resource_t *rsc, gboolean details);
extern void print_rsc_to_node(
const char *pre_text, rsc_to_node_t *cons, gboolean details);
extern void print_rsc_colocation(
const char *pre_text, rsc_colocation_t *cons, gboolean details);
extern void print_color(
const char *pre_text, color_t *color, gboolean details);
extern void print_color_details(
const char *pre_text, struct color_shared_s *color, gboolean details);
extern void print_action(
const char *pre_text, action_t *action, gboolean details);
extern void log_action(
- int log_level, const char *pre_text, action_t *action, gboolean details);
+ unsigned int log_level, const char *pre_text, action_t *action, gboolean details);
/* Sorting functions */
extern gint sort_rsc_priority(gconstpointer a, gconstpointer b);
extern gint sort_cons_strength(gconstpointer a, gconstpointer b);
extern gint sort_color_weight(gconstpointer a, gconstpointer b);
extern gint sort_node_weight(gconstpointer a, gconstpointer b);
extern gint sort_action_id(gconstpointer a, gconstpointer b);
/* enum 2 text functions (mostly used by print_*) */
extern const char *contype2text(enum con_type type);
extern const char *strength2text(enum con_strength strength);
/*extern const char *modifier2text(enum con_modifier modifier); */
extern const char *task2text(enum action_tasks task);
extern enum action_tasks text2task(const char *task);
extern crm_data_t *find_rsc_op_entry(resource_t *rsc, const char *key);
extern action_t *custom_action(
resource_t *rsc, char *key, const char *task,
node_t *on_node, gboolean optional, pe_working_set_t *data_set);
#define stop_action(rsc, node, optional) custom_action( \
rsc, stop_key(rsc), CRMD_ACTION_STOP, node, optional, data_set);
#define stopped_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOPPED, 0)
#define stop_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STOP, 0)
#define start_action(rsc, node, optional) custom_action( \
rsc, start_key(rsc), CRMD_ACTION_START, node, optional, data_set)
#define started_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_STARTED, 0)
#define start_key(rsc) generate_op_key(rsc->id, CRMD_ACTION_START, 0)
extern GListPtr find_actions(GListPtr input, const char *key, node_t *on_node);
extern void set_id(crm_data_t *xml_obj, const char *prefix, int child);
extern const char *ordering_type2text(enum pe_ordering type);
/* free the various structures */
extern void pe_free_nodes(GListPtr nodes);
extern void pe_free_colors(GListPtr colors);
extern void pe_free_rsc_colocation(rsc_colocation_t *cons);
extern void pe_free_rsc_to_node(rsc_to_node_t *cons);
extern void pe_free_shallow(GListPtr alist);
extern void pe_free_shallow_adv(GListPtr alist, gboolean with_data);
extern void pe_free_resources(GListPtr resources);
extern void pe_free_actions(GListPtr actions);
extern void pe_free_ordering(GListPtr constraints);
/* Helper macros to avoid NULL pointers */
#define safe_val(def, x,y) (x?x->y:def)
#define safe_val3(def, t,u,v) (t?t->u?t->u->v:def:def)
#define safe_val4(def, t,u,v,w) (t?t->u?t->u->v?t->u->v->w:def:def:def)
#define safe_val5(def, t,u,v,w,x) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x:def:def:def:def)
#define safe_val6(def, t,u,v,w,x,y) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y:def:def:def:def:def)
#define safe_val7(def, t,u,v,w,x,y,z) (t?t->u?t->u->v?t->u->v->w?t->u->v->w->x?t->u->v->w->x->y?t->u->v->w->x->y->z:def:def:def:def:def:def)
#endif
diff --git a/crm/pengine/utils.c b/crm/pengine/utils.c
index f8fdcf3b87..655c9a16a4 100644
--- a/crm/pengine/utils.c
+++ b/crm/pengine/utils.c
@@ -1,1466 +1,1466 @@
-/* $Id: utils.c,v 1.88 2005/06/27 11:21:23 andrew Exp $ */
+/* $Id: utils.c,v 1.89 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <glib.h>
#include <pengine.h>
#include <pe_utils.h>
void print_str_str(gpointer key, gpointer value, gpointer user_data);
gboolean ghash_free_str_str(gpointer key, gpointer value, gpointer user_data);
void unpack_operation(
action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set);
/* only for rsc_colocation constraints */
rsc_colocation_t *
invert_constraint(rsc_colocation_t *constraint)
{
rsc_colocation_t *inverted_con = NULL;
crm_debug_3("Inverting constraint");
if(constraint == NULL) {
pe_err("Cannot invert NULL constraint");
return NULL;
}
crm_malloc0(inverted_con, sizeof(rsc_colocation_t));
if(inverted_con == NULL) {
return NULL;
}
inverted_con->id = constraint->id;
inverted_con->strength = constraint->strength;
/* swap the direction */
inverted_con->rsc_lh = constraint->rsc_rh;
inverted_con->rsc_rh = constraint->rsc_lh;
crm_action_debug_3(
print_rsc_colocation("Inverted constraint", inverted_con, FALSE));
return inverted_con;
}
/* are the contents of list1 and list2 equal
* nodes with weight < 0 are ignored if filter == TRUE
*
* slow but linear
*
*/
gboolean
node_list_eq(GListPtr list1, GListPtr list2, gboolean filter)
{
node_t *other_node;
GListPtr lhs = list1;
GListPtr rhs = list2;
slist_iter(
node, node_t, lhs, lpc,
if(node == NULL || (filter && node->weight < 0)) {
continue;
}
other_node = (node_t*)
pe_find_node(rhs, node->details->uname);
if(other_node == NULL || other_node->weight < 0) {
return FALSE;
}
);
lhs = list2;
rhs = list1;
slist_iter(
node, node_t, lhs, lpc,
if(node == NULL || (filter && node->weight < 0)) {
continue;
}
other_node = (node_t*)
pe_find_node(rhs, node->details->uname);
if(other_node == NULL || other_node->weight < 0) {
return FALSE;
}
);
return TRUE;
}
/* the intersection of list1 and list2
*/
GListPtr
node_list_and(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
unsigned lpc = 0;
for(lpc = 0; lpc < g_list_length(list1); lpc++) {
node_t *node = (node_t*)g_list_nth_data(list1, lpc);
node_t *other_node = pe_find_node(list2, node->details->uname);
node_t *new_node = NULL;
if(other_node != NULL) {
new_node = node_copy(node);
}
if(new_node != NULL) {
new_node->weight = merge_weights(
new_node->weight, other_node->weight);
if(filter && new_node->weight < 0) {
crm_free(new_node);
new_node = NULL;
}
}
if(new_node != NULL) {
result = g_list_append(result, new_node);
}
}
return result;
}
/* list1 - list2 */
GListPtr
node_list_minus(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
node, node_t, list1, lpc,
node_t *other_node = pe_find_node(list2, node->details->uname);
node_t *new_node = NULL;
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
crm_debug_3("Minus result len: %d", g_list_length(result));
return result;
}
/* list1 + list2 - (intersection of list1 and list2) */
GListPtr
node_list_xor(GListPtr list1, GListPtr list2, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
node, node_t, list1, lpc,
node_t *new_node = NULL;
node_t *other_node = (node_t*)
pe_find_node(list2, node->details->uname);
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
slist_iter(
node, node_t, list2, lpc,
node_t *new_node = NULL;
node_t *other_node = (node_t*)
pe_find_node(list1, node->details->uname);
if(node == NULL || other_node != NULL
|| (filter && node->weight < 0)) {
continue;
}
new_node = node_copy(node);
result = g_list_append(result, new_node);
);
crm_debug_3("Xor result len: %d", g_list_length(result));
return result;
}
GListPtr
node_list_or(GListPtr list1, GListPtr list2, gboolean filter)
{
node_t *other_node = NULL;
GListPtr result = NULL;
gboolean needs_filter = FALSE;
result = node_list_dup(list1, filter);
slist_iter(
node, node_t, list2, lpc,
if(node == NULL) {
continue;
}
other_node = (node_t*)pe_find_node(
result, node->details->uname);
if(other_node != NULL) {
other_node->weight = merge_weights(
other_node->weight, node->weight);
if(filter && node->weight < 0) {
needs_filter = TRUE;
}
} else if(filter == FALSE || node->weight >= 0) {
node_t *new_node = node_copy(node);
result = g_list_append(result, new_node);
}
);
/* not the neatest way, but the most expedient for now */
if(filter && needs_filter) {
GListPtr old_result = result;
result = node_list_dup(old_result, filter);
pe_free_shallow_adv(old_result, TRUE);
}
return result;
}
GListPtr
node_list_dup(GListPtr list1, gboolean filter)
{
GListPtr result = NULL;
slist_iter(
this_node, node_t, list1, lpc,
node_t *new_node = NULL;
if(filter && this_node->weight < 0) {
continue;
}
new_node = node_copy(this_node);
if(new_node != NULL) {
result = g_list_append(result, new_node);
}
);
return result;
}
node_t *
node_copy(node_t *this_node)
{
node_t *new_node = NULL;
CRM_DEV_ASSERT(this_node != NULL);
if(this_node == NULL) {
pe_err("Failed copy of <null> node.");
return NULL;
}
crm_malloc0(new_node, sizeof(node_t));
CRM_DEV_ASSERT(new_node != NULL);
if(new_node == NULL) {
return NULL;
}
crm_debug_5("Copying %p (%s) to %p",
this_node, this_node->details->uname, new_node);
new_node->weight = this_node->weight;
new_node->fixed = this_node->fixed;
new_node->details = this_node->details;
return new_node;
}
/*
* Create a new color with the contents of "nodes" as the list of
* possible nodes that resources with this color can be run on.
*
* Typically, when creating a color you will provide the node list from
* the resource you will first assign the color to.
*
* If "colors" != NULL, it will be added to that list
* If "resources" != NULL, it will be added to every provisional resource
* in that list
*/
color_t *
create_color(
pe_working_set_t *data_set, resource_t *resource, GListPtr node_list)
{
color_t *new_color = NULL;
crm_debug_5("Creating color");
crm_malloc0(new_color, sizeof(color_t));
if(new_color == NULL) {
return NULL;
}
new_color->id = data_set->color_id++;
new_color->local_weight = 1.0;
crm_debug_5("Creating color details");
crm_malloc0(new_color->details, sizeof(struct color_shared_s));
if(new_color->details == NULL) {
crm_free(new_color);
return NULL;
}
new_color->details->id = new_color->id;
new_color->details->highest_priority = -1;
new_color->details->chosen_node = NULL;
new_color->details->candidate_nodes = NULL;
new_color->details->allocated_resources = NULL;
new_color->details->pending = TRUE;
if(resource != NULL) {
crm_debug_5("populating node list");
new_color->details->highest_priority = resource->priority;
new_color->details->candidate_nodes =
node_list_dup(node_list, TRUE);
}
crm_action_debug_3(print_color("Created color", new_color, TRUE));
CRM_DEV_ASSERT(data_set != NULL);
if(crm_assert_failed == FALSE) {
data_set->colors = g_list_append(data_set->colors, new_color);
}
return new_color;
}
color_t *
copy_color(color_t *a_color)
{
color_t *color_copy = NULL;
if(a_color == NULL) {
pe_err("Cannot copy NULL");
return NULL;
}
crm_malloc0(color_copy, sizeof(color_t));
if(color_copy != NULL) {
color_copy->id = a_color->id;
color_copy->details = a_color->details;
color_copy->local_weight = 1.0;
}
return color_copy;
}
resource_t *
pe_find_resource(GListPtr rsc_list, const char *id)
{
unsigned lpc = 0;
resource_t *rsc = NULL;
resource_t *child_rsc = NULL;
crm_debug_4("Looking for %s in %d objects", id, g_list_length(rsc_list));
for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) {
rsc = g_list_nth_data(rsc_list, lpc);
if(rsc != NULL && safe_str_eq(rsc->id, id)){
crm_debug_4("Found a match for %s", id);
return rsc;
}
}
for(lpc = 0; lpc < g_list_length(rsc_list); lpc++) {
rsc = g_list_nth_data(rsc_list, lpc);
child_rsc = rsc->fns->find_child(rsc, id);
if(child_rsc != NULL) {
crm_debug_4("Found a match for %s in %s",
id, rsc->id);
return child_rsc;
}
}
/* error */
return NULL;
}
node_t *
pe_find_node(GListPtr nodes, const char *uname)
{
unsigned lpc = 0;
node_t *node = NULL;
for(lpc = 0; lpc < g_list_length(nodes); lpc++) {
node = g_list_nth_data(nodes, lpc);
if(node != NULL && safe_str_eq(node->details->uname, uname)) {
return node;
}
}
/* error */
return NULL;
}
node_t *
pe_find_node_id(GListPtr nodes, const char *id)
{
unsigned lpc = 0;
node_t *node = NULL;
for(lpc = 0; lpc < g_list_length(nodes); lpc++) {
node = g_list_nth_data(nodes, lpc);
if(safe_str_eq(node->details->id, id)) {
return node;
}
}
/* error */
return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b);
color_t *
find_color(GListPtr candidate_colors, color_t *other_color)
{
GListPtr tmp = g_list_find_custom(candidate_colors, other_color,
gslist_color_compare);
if(tmp != NULL) {
return (color_t *)tmp->data;
}
return NULL;
}
gint gslist_color_compare(gconstpointer a, gconstpointer b)
{
const color_t *color_a = (const color_t*)a;
const color_t *color_b = (const color_t*)b;
/* crm_debug_5("%d vs. %d", a?color_a->id:-2, b?color_b->id:-2); */
if(a == b) {
return 0;
} else if(a == NULL || b == NULL) {
return 1;
} else if(color_a->id == color_b->id) {
return 0;
}
return 1;
}
gint sort_rsc_priority(gconstpointer a, gconstpointer b)
{
const resource_t *resource1 = (const resource_t*)a;
const resource_t *resource2 = (const resource_t*)b;
if(a == NULL && b == NULL) { return 0; }
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(resource1->priority > resource2->priority) {
return -1;
}
if(resource1->priority < resource2->priority) {
return 1;
}
return 0;
}
/* lowest to highest */
gint sort_action_id(gconstpointer a, gconstpointer b)
{
const action_wrapper_t *action_wrapper2 = (const action_wrapper_t*)a;
const action_wrapper_t *action_wrapper1 = (const action_wrapper_t*)b;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(action_wrapper1->action->id > action_wrapper2->action->id) {
return -1;
}
if(action_wrapper1->action->id < action_wrapper2->action->id) {
return 1;
}
return 0;
}
gint sort_cons_strength(gconstpointer a, gconstpointer b)
{
const rsc_colocation_t *rsc_constraint1 = (const rsc_colocation_t*)a;
const rsc_colocation_t *rsc_constraint2 = (const rsc_colocation_t*)b;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(rsc_constraint1->strength > rsc_constraint2->strength) {
return 1;
}
if(rsc_constraint1->strength < rsc_constraint2->strength) {
return -1;
}
return 0;
}
gint sort_color_weight(gconstpointer a, gconstpointer b)
{
const color_t *color1 = (const color_t*)a;
const color_t *color2 = (const color_t*)b;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
if(color1->local_weight > color2->local_weight) {
return -1;
}
if(color1->local_weight < color2->local_weight) {
return 1;
}
return 0;
}
/* return -1 if 'a' is more preferred
* return 1 if 'b' is more preferred
*/
gint sort_node_weight(gconstpointer a, gconstpointer b)
{
const node_t *node1 = (const node_t*)a;
const node_t *node2 = (const node_t*)b;
float node1_weight = 0;
float node2_weight = 0;
if(a == NULL) { return 1; }
if(b == NULL) { return -1; }
node1_weight = node1->weight;
node2_weight = node2->weight;
if(node1->details->unclean || node1->details->shutdown) {
node1_weight = -INFINITY;
}
if(node2->details->unclean || node2->details->shutdown) {
node2_weight = -INFINITY;
}
if(node1_weight > node2_weight) {
crm_debug_4("%s (%f) > %s (%f) : weight",
node1->details->id, node1_weight,
node2->details->id, node2_weight);
return -1;
}
if(node1_weight < node2_weight) {
crm_debug_4("%s (%f) < %s (%f) : weight",
node1->details->id, node1_weight,
node2->details->id, node2_weight);
return 1;
}
/* now try to balance resources across the cluster */
if(node1->details->num_resources
< node2->details->num_resources) {
crm_debug_4("%s (%d) < %s (%d) : resources",
node1->details->id, node1->details->num_resources,
node2->details->id, node2->details->num_resources);
return -1;
} else if(node1->details->num_resources
> node2->details->num_resources) {
crm_debug_4("%s (%d) > %s (%d) : resources",
node1->details->id, node1->details->num_resources,
node2->details->id, node2->details->num_resources);
return 1;
}
crm_debug_4("%s = %s", node1->details->id, node2->details->id);
return 0;
}
action_t *
custom_action(resource_t *rsc, char *key, const char *task, node_t *on_node,
gboolean optional, pe_working_set_t *data_set)
{
action_t *action = NULL;
GListPtr possible_matches = NULL;
CRM_DEV_ASSERT(key != NULL);
if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(task != NULL);
if(crm_assert_failed) { return NULL; }
if(rsc != NULL) {
possible_matches = find_actions(rsc->actions, key, on_node);
}
if(possible_matches != NULL) {
crm_free(key);
if(g_list_length(possible_matches) > 1) {
pe_warn("Action %s for %s on %s exists %d times",
task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>",
g_list_length(possible_matches));
}
action = g_list_nth_data(possible_matches, 0);
crm_debug_4("Found existing action (%d) %s for %s on %s",
action->id, task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>");
}
if(action == NULL) {
crm_debug_4("Creating action %s for %s on %s",
task, rsc?rsc->id:"<NULL>",
on_node?on_node->details->uname:"<NULL>");
crm_malloc0(action, sizeof(action_t));
if(action != NULL) {
action->id = data_set->action_id++;
action->rsc = rsc;
action->task = task;
action->node = on_node;
action->actions_before = NULL;
action->actions_after = NULL;
action->failure_is_fatal = TRUE;
action->pseudo = FALSE;
action->dumped = FALSE;
action->runnable = TRUE;
action->processed = FALSE;
action->optional = TRUE;
action->seen_count = 0;
action->extra = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
data_set->actions = g_list_append(
data_set->actions, action);
action->uuid = key;
if(rsc != NULL) {
action->op_entry = find_rsc_op_entry(rsc, key);
unpack_operation(
action, action->op_entry, data_set);
rsc->actions = g_list_append(
rsc->actions, action);
}
crm_debug_4("Action %d created", action->id);
}
}
if(optional == FALSE) {
crm_debug_2("Action %d marked manditory", action->id);
action->optional = FALSE;
}
if(rsc != NULL) {
if(action->node == NULL) {
action->runnable = FALSE;
} else if(action->node->details->online == FALSE) {
pe_warn("Action %d %s for %s on %s is unrunnable",
action->id,
task, rsc?rsc->id:"<NULL>",
action->node?action->node->details->uname:"<none>");
action->runnable = FALSE;
} else if(action->needs == rsc_req_nothing) {
action->runnable = TRUE;
} else if(data_set->have_quorum == FALSE
&& data_set->no_quorum_policy == no_quorum_stop) {
action->runnable = FALSE;
} else {
action->runnable = TRUE;
}
switch(text2task(action->task)) {
case stop_rsc:
rsc->stopping = TRUE;
break;
case start_rsc:
rsc->starting = FALSE;
if(action->runnable) {
rsc->starting = TRUE;
}
break;
default:
break;
}
}
return action;
}
void
unpack_operation(
action_t *action, crm_data_t *xml_obj, pe_working_set_t* data_set)
{
int lpc = 0;
const char *value = NULL;
const char *fields[] = {
"interval",
"timeout",
"start_delay",
};
if(xml_obj != NULL) {
value = crm_element_value(xml_obj, "prereq");
}
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_START)) {
value = crm_element_value(action->rsc->xml, "start_prereq");
}
if(value == NULL && safe_str_neq(action->task, CRMD_ACTION_START)) {
/* todo: integrate stop as an option? */
action->needs = rsc_req_nothing;
value = "nothing (default)";
} else if(safe_str_eq(value, "nothing")) {
action->needs = rsc_req_nothing;
} else if(safe_str_eq(value, "quorum")) {
action->needs = rsc_req_quorum;
} else if(safe_str_eq(value, "fencing")) {
action->needs = rsc_req_stonith;
} else if(data_set->no_quorum_policy == no_quorum_ignore) {
action->needs = rsc_req_nothing;
value = "nothing (default)";
} else if(data_set->no_quorum_policy == no_quorum_freeze
&& data_set->stonith_enabled) {
action->needs = rsc_req_stonith;
value = "fencing (default)";
} else {
action->needs = rsc_req_quorum;
value = "quorum (default)";
}
crm_debug_2("\tAction %s requires: %s", action->task, value);
value = NULL;
if(xml_obj != NULL) {
value = crm_element_value(xml_obj, "on_fail");
}
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
value = crm_element_value(action->rsc->xml, "on_stopfail");
}
if(value == NULL) {
} else if(safe_str_eq(value, "fence")) {
action->on_fail = action_fail_fence;
value = "node fencing";
} else if(safe_str_eq(value, "stop")) {
action->on_fail = action_fail_stop;
value = "resource nothing";
} else if(safe_str_eq(value, "nothing")) {
action->on_fail = action_fail_nothing;
value = "nothing";
} else if(safe_str_eq(value, "ignore")) {
action->on_fail = action_fail_nothing;
value = "nothing";
} else {
pe_err("Resource %s: Unknown failure type (%s)",
action->rsc->id, value);
value = NULL;
}
/* defaults */
if(value == NULL && safe_str_eq(action->task, CRMD_ACTION_STOP)) {
if(data_set->stonith_enabled) {
action->on_fail = action_fail_fence;
value = "resource fence (default)";
} else {
action->on_fail = action_fail_block;
value = "resource block (default)";
}
} else if(value == NULL) {
action->on_fail = action_fail_stop;
value = "resource stop (default)";
}
crm_debug_2("\t%s failure results in: %s", action->task, value);
if(xml_obj == NULL) {
return;
}
for(;lpc < DIMOF(fields); lpc++) {
value = crm_element_value(xml_obj, fields[lpc]);
add_hash_param(action->extra, fields[lpc], value);
}
unpack_instance_attributes(xml_obj, action->extra);
/* if(safe_str_eq(native_data->agent->class, "stonith")) { */
/* if(rsc->start_needs == rsc_req_stonith) { */
/* pe_err("Stonith resources (eg. %s) cannot require" */
/* " fencing to start", rsc->id); */
/* } */
/* rsc->start_needs = rsc_req_quorum; */
/* } */
}
crm_data_t *
find_rsc_op_entry(resource_t *rsc, const char *key)
{
const char *name = NULL;
const char *interval = NULL;
char *match_key = NULL;
crm_data_t *op = NULL;
xml_child_iter(
rsc->ops_xml, operation, "op",
name = crm_element_value(operation, "name");
interval = crm_element_value(operation, "interval");
match_key = generate_op_key(rsc->id,name,crm_get_msec(interval));
crm_debug_2("Matching %s with %s", key, match_key);
if(safe_str_eq(key, match_key)) {
op = operation;
}
crm_free(match_key);
if(op != NULL) {
break;
}
);
crm_debug_2("No matching for %s", key);
return op;
}
const char *
strength2text(enum con_strength strength)
{
const char *result = "<unknown>";
switch(strength)
{
case pecs_ignore:
result = "ignore";
break;
case pecs_must:
result = XML_STRENGTH_VAL_MUST;
break;
case pecs_must_not:
result = XML_STRENGTH_VAL_MUSTNOT;
break;
case pecs_startstop:
result = "start/stop";
break;
}
return result;
}
const char *
ordering_type2text(enum pe_ordering type)
{
const char *result = "<unknown>";
switch(type)
{
case pe_ordering_manditory:
result = "manditory";
break;
case pe_ordering_restart:
result = "restart";
break;
case pe_ordering_recover:
result = "recover";
break;
case pe_ordering_optional:
result = "optional";
break;
}
return result;
}
enum action_tasks
text2task(const char *task)
{
if(safe_str_eq(task, CRMD_ACTION_STOP)) {
return stop_rsc;
} else if(safe_str_eq(task, CRMD_ACTION_STOPPED)) {
return stopped_rsc;
} else if(safe_str_eq(task, CRMD_ACTION_START)) {
return start_rsc;
} else if(safe_str_eq(task, CRMD_ACTION_STARTED)) {
return started_rsc;
} else if(safe_str_eq(task, CRM_OP_SHUTDOWN)) {
return shutdown_crm;
} else if(safe_str_eq(task, CRM_OP_FENCE)) {
return stonith_node;
} else if(safe_str_eq(task, CRMD_ACTION_MON)) {
return monitor_rsc;
}
pe_err("Unsupported action: %s", task);
return no_action;
}
const char *
task2text(enum action_tasks task)
{
const char *result = "<unknown>";
switch(task)
{
case no_action:
result = "no_action";
break;
case stop_rsc:
result = CRMD_ACTION_STOP;
break;
case stopped_rsc:
result = CRMD_ACTION_STOPPED;
break;
case start_rsc:
result = CRMD_ACTION_START;
break;
case started_rsc:
result = CRMD_ACTION_STARTED;
break;
case shutdown_crm:
result = CRM_OP_SHUTDOWN;
break;
case stonith_node:
result = CRM_OP_FENCE;
break;
case monitor_rsc:
result = CRMD_ACTION_MON;
break;
}
return result;
}
void
print_node(const char *pre_text, node_t *node, gboolean details)
{
if(node == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%sNode %s: (weight=%f, fixed=%s)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
node->details==NULL?"error ":node->details->online?"":"Unavailable/Unclean ",
node->details->uname,
node->weight,
node->fixed?"True":"False");
if(details && node != NULL && node->details != NULL) {
char *pe_mutable = crm_strdup("\t\t");
crm_debug_4("\t\t===Node Attributes");
g_hash_table_foreach(node->details->attrs,
print_str_str, pe_mutable);
crm_free(pe_mutable);
crm_debug_4("\t\t=== Resources");
slist_iter(
rsc, resource_t, node->details->running_rsc, lpc,
print_resource("\t\t", rsc, FALSE);
);
}
}
/*
* Used by the HashTable for-loop
*/
void print_str_str(gpointer key, gpointer value, gpointer user_data)
{
crm_debug_4("%s%s %s ==> %s",
user_data==NULL?"":(char*)user_data,
user_data==NULL?"":": ",
(char*)key,
(char*)value);
}
void
print_color_details(const char *pre_text,
struct color_shared_s *color,
gboolean details)
{
if(color == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%sColor %d: node=%s (from %d candidates)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->chosen_node==NULL?"<unset>":color->chosen_node->details->uname,
g_list_length(color->candidate_nodes));
if(details) {
slist_iter(node, node_t, color->candidate_nodes, lpc,
print_node("\t", node, FALSE));
}
}
void
print_color(const char *pre_text, color_t *color, gboolean details)
{
if(color == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%sColor %d: (weight=%f, node=%s, possible=%d)",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
color->id,
color->local_weight,
safe_val5("<unset>",color,details,chosen_node,details,uname),
g_list_length(color->details->candidate_nodes));
if(details) {
print_color_details("\t", color->details, details);
}
}
void
print_rsc_to_node(const char *pre_text, rsc_to_node_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%s Constraint %s (%p) - %d nodes:",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
"rsc_to_node",
cons->id, cons,
g_list_length(cons->node_list_rh));
if(details == FALSE) {
crm_debug_4("\t%s (score=%f : node placement rule)",
safe_val3(NULL, cons, rsc_lh, id),
cons->weight);
slist_iter(
node, node_t, cons->node_list_rh, lpc,
print_node("\t\t-->", node, FALSE)
);
}
}
void
print_rsc_colocation(const char *pre_text, rsc_colocation_t *cons, gboolean details)
{
if(cons == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
crm_debug_4("%s%s%s Constraint %s (%p):",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
XML_CONS_TAG_RSC_DEPEND, cons->id, cons);
if(details == FALSE) {
crm_debug_4("\t%s --> %s, %s",
safe_val3(NULL, cons, rsc_lh, id),
safe_val3(NULL, cons, rsc_rh, id),
strength2text(cons->strength));
}
}
void
print_resource(const char *pre_text, resource_t *rsc, gboolean details)
{
if(rsc == NULL) {
crm_debug_4("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
rsc->fns->dump(rsc, pre_text, details);
}
void
print_action(const char *pre_text, action_t *action, gboolean details)
{
log_action(LOG_DEBUG_3, pre_text, action, details);
}
#define util_log(fmt...) do_crm_log(log_level, __FILE__, __FUNCTION__, fmt)
void
-log_action(int log_level, const char *pre_text, action_t *action, gboolean details)
+log_action(unsigned int log_level, const char *pre_text, action_t *action, gboolean details)
{
if(action == NULL) {
util_log("%s%s: <NULL>",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ");
return;
}
switch(text2task(action->task)) {
case stonith_node:
case shutdown_crm:
crm_log_maybe(log_level, "%s%s%sAction %d: %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->pseudo?"Pseduo ":action->optional?"Optional ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->task,
safe_val4(NULL, action, node, details, uname));
break;
default:
crm_log_maybe(log_level, "%s%s%sAction %d: %s %s @ %s",
pre_text==NULL?"":pre_text,
pre_text==NULL?"":": ",
action->optional?"Optional ":action->pseudo?"Pseduo ":action->runnable?action->processed?"":"(Provisional) ":"!!Non-Startable!! ",
action->id, action->task,
safe_val3(NULL, action, rsc, id),
safe_val4(NULL, action, node, details, uname));
break;
}
if(details) {
crm_log_maybe(log_level+1, "\t\t====== Preceeding Actions");
slist_iter(
other, action_wrapper_t, action->actions_before, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
#if 1
crm_log_maybe(log_level+1, "\t\t====== Subsequent Actions");
slist_iter(
other, action_wrapper_t, action->actions_after, lpc,
log_action(log_level+1, "\t\t", other->action, FALSE);
);
#endif
crm_log_maybe(log_level+1, "\t\t====== End");
} else {
crm_log_maybe(log_level, "\t\t(seen=%d, before=%d, after=%d)",
action->seen_count,
g_list_length(action->actions_before),
g_list_length(action->actions_after));
}
}
void
pe_free_nodes(GListPtr nodes)
{
GListPtr iterator = nodes;
while(iterator != NULL) {
node_t *node = (node_t*)iterator->data;
struct node_shared_s *details = node->details;
iterator = iterator->next;
crm_debug_5("deleting node");
crm_debug_5("%s is being deleted", details->uname);
print_node("delete", node, FALSE);
if(details != NULL) {
if(details->attrs != NULL) {
g_hash_table_destroy(details->attrs);
}
pe_free_shallow_adv(details->running_rsc, FALSE);
crm_free(details);
}
crm_free(node);
}
if(nodes != NULL) {
g_list_free(nodes);
}
}
void
pe_free_colors(GListPtr colors)
{
GListPtr iterator = colors;
while(iterator != NULL) {
color_t *color = (color_t *)iterator->data;
struct color_shared_s *details = color->details;
iterator = iterator->next;
if(details != NULL) {
pe_free_shallow(details->candidate_nodes);
pe_free_shallow_adv(details->allocated_resources, FALSE);
crm_free(details->chosen_node);
crm_free(details);
}
crm_free(color);
}
if(colors != NULL) {
g_list_free(colors);
}
}
void
pe_free_shallow(GListPtr alist)
{
pe_free_shallow_adv(alist, TRUE);
}
void
pe_free_shallow_adv(GListPtr alist, gboolean with_data)
{
GListPtr item;
GListPtr item_next = alist;
while(item_next != NULL) {
item = item_next;
item_next = item_next->next;
if(with_data) {
/* crm_debug_5("freeing %p", item->data); */
crm_free(item->data);
}
item->data = NULL;
item->next = NULL;
g_list_free(item);
}
}
void
pe_free_resources(GListPtr resources)
{
resource_t *rsc = NULL;
GListPtr iterator = resources;
while(iterator != NULL) {
iterator = iterator;
rsc = (resource_t *)iterator->data;
iterator = iterator->next;
rsc->fns->free(rsc);
}
if(resources != NULL) {
g_list_free(resources);
}
}
void
pe_free_actions(GListPtr actions)
{
GListPtr iterator = actions;
while(iterator != NULL) {
action_t *action = (action_t *)iterator->data;
iterator = iterator->next;
pe_free_shallow(action->actions_before);/* action_warpper_t* */
pe_free_shallow(action->actions_after); /* action_warpper_t* */
g_hash_table_destroy(action->extra);
crm_free(action->uuid);
crm_free(action);
}
if(actions != NULL) {
g_list_free(actions);
}
}
void
pe_free_ordering(GListPtr constraints)
{
GListPtr iterator = constraints;
while(iterator != NULL) {
order_constraint_t *order = iterator->data;
iterator = iterator->next;
crm_free(order->lh_action_task);
crm_free(order->rh_action_task);
crm_free(order);
}
if(constraints != NULL) {
g_list_free(constraints);
}
}
void
pe_free_rsc_colocation(rsc_colocation_t *cons)
{
if(cons != NULL) {
crm_debug_4("Freeing constraint %s (%p)", cons->id, cons);
crm_free(cons);
}
}
void
pe_free_rsc_to_node(rsc_to_node_t *cons)
{
if(cons != NULL) {
pe_free_shallow(cons->node_list_rh);
crm_free(cons);
}
}
GListPtr
find_actions(GListPtr input, const char *key, node_t *on_node)
{
GListPtr result = NULL;
CRM_DEV_ASSERT(key != NULL);
slist_iter(
action, action_t, input, lpc,
crm_debug_5("Matching %s against %s", key, action->uuid);
if(safe_str_neq(key, action->uuid)) {
continue;
} else if(on_node == NULL) {
result = g_list_append(result, action);
} else if(action->node == NULL) {
/* skip */
crm_debug_2("While looking for %s action on %s, "
"found an unallocated one. Assigning"
" it to the requested node...",
key, on_node->details->uname);
action->node = on_node;
result = g_list_append(result, action);
} else if(safe_str_eq(on_node->details->id,
action->node->details->id)) {
result = g_list_append(result, action);
}
);
return result;
}
void
set_id(crm_data_t * xml_obj, const char *prefix, int child)
{
int id_len = 0;
gboolean use_prefix = TRUE;
gboolean use_child = TRUE;
char *new_id = NULL;
const char *id = crm_element_value(xml_obj, XML_ATTR_ID);
id_len = 1 + strlen(id);
if(child > 999) {
pe_err("Are you insane?!?"
" The CRM does not support > 1000 children per resource");
return;
} else if(child < 0) {
use_child = FALSE;
} else {
id_len += 4; /* child */
}
if(prefix == NULL || safe_str_eq(id, prefix)) {
use_prefix = FALSE;
} else {
id_len += (1 + strlen(prefix));
}
crm_malloc0(new_id, id_len);
if(use_child) {
snprintf(new_id, id_len, "%s%s%s:%d",
use_prefix?prefix:"", use_prefix?":":"", id, child);
} else {
snprintf(new_id, id_len, "%s%s%s",
use_prefix?prefix:"", use_prefix?":":"", id);
}
crm_xml_add(xml_obj, XML_ATTR_ID, new_id);
crm_free(new_id);
}
float
merge_weights(float w1, float w2)
{
float result = w1 + w2;
if(w1 <= -INFINITY || w2 <= -INFINITY) {
if(w1 == INFINITY || w2 == INFINITY) {
pe_warn("-INFINITY + INFINITY == -INFINITY");
}
return -INFINITY;
} else if(w1 >= INFINITY || w2 >= INFINITY) {
return INFINITY;
}
/* detect wrap-around */
if(result > 0) {
if(w1 <= 0 && w2 < 0) {
result = -INFINITY;
}
} else if(w1 > 0 && w2 > 0) {
result = INFINITY;
}
/* detect +/- INFINITY */
if(result >= INFINITY) {
result = INFINITY;
} else if(result <= -INFINITY) {
result = -INFINITY;
}
return result;
}
diff --git a/crm/tengine/tengine.h b/crm/tengine/tengine.h
index 0eeb47e8c9..b27076574a 100644
--- a/crm/tengine/tengine.h
+++ b/crm/tengine/tengine.h
@@ -1,163 +1,163 @@
-/* $Id: tengine.h,v 1.24 2005/06/27 11:13:05 andrew Exp $ */
+/* $Id: tengine.h,v 1.25 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#ifndef TENGINE__H
#define TENGINE__H
#include <clplumbing/ipc.h>
#include <fencing/stonithd_api.h>
extern IPC_Channel *crm_ch;
extern GListPtr graph;
extern GMainLoop* mainloop;
extern gboolean in_transition;
typedef enum {
action_type_pseudo,
action_type_rsc,
action_type_crm
} action_type_e;
typedef enum te_reason_e {
te_update,
te_done,
te_halt,
te_abort,
te_abort_confirmed,
te_failed,
te_timeout,
} te_reason_t;
typedef enum te_fsa_states_e {
s_idle,
s_in_transition,
s_abort_pending,
s_invalid
} te_fsa_state_t;
typedef enum te_fsa_inputs_e {
i_transition,
i_cancel,
i_complete,
i_cib_complete,
i_cib_confirm,
i_cib_notify,
i_invalid
} te_fsa_input_t;
extern const te_fsa_state_t te_state_matrix[i_invalid][s_invalid];
extern te_fsa_state_t te_fsa_state;
typedef struct synapse_s {
int id;
gboolean triggers_complete;
gboolean complete;
gboolean confirmed;
GListPtr actions; /* action_t* */
GListPtr inputs; /* action_t* */
} synapse_t;
typedef struct te_timer_s te_timer_t;
typedef struct action_s {
int id;
int timeout;
int interval;
te_timer_t *timer;
action_type_e type;
gboolean invoked;
gboolean complete;
gboolean can_fail;
crm_data_t *xml;
} action_t;
enum timer_reason {
timeout_action,
timeout_action_warn,
timeout_timeout,
};
struct te_timer_s
{
int source_id;
int timeout;
enum timer_reason reason;
action_t *action;
};
/* tengine */
extern gboolean initialize_graph(void);
extern gboolean process_graph_event(crm_data_t *event, const char *event_node);
/* const char *event_node, const char *event_rsc, const char *rsc_state,
* const char *event_action, const char *event_rc, const char *op_status); */
extern int match_graph_event(
action_t *action, crm_data_t *event, const char *event_node);
extern int match_down_event(const char *target, const char *filter, int rc);
extern gboolean initiate_transition(void);
extern gboolean cib_action_update(action_t *action, int status);
/* utils */
-extern void print_state(int log_level);
+extern void print_state(unsigned int log_level);
extern void send_complete(const char *text, crm_data_t *msg,
te_reason_t reason, te_fsa_input_t input);
extern gboolean stop_te_timer(te_timer_t *timer);
extern gboolean start_te_timer(te_timer_t *timer);
extern const char *get_rsc_state(const char *task, op_status_t status);
/* unpack */
extern gboolean unpack_graph(crm_data_t *xml_graph);
extern gboolean extract_event(crm_data_t *msg);
extern gboolean process_te_message(
HA_Message * msg, crm_data_t *xml_data, IPC_Channel *sender);
extern uint transition_idle_timeout;
extern uint default_transition_idle_timeout;
extern te_timer_t *transition_timer;
extern cib_t *te_cib_conn;
extern const char *actiontype2text(action_type_e type);
extern void tengine_stonith_callback(stonith_ops_t * op, void * private_data);
extern void tengine_stonith_connection_destroy(gpointer user_data);
extern gboolean tengine_stonith_dispatch(IPC_Channel *sender, void *user_data);
extern void check_for_completion(void);
void process_trigger(int action_id);
#ifdef TESTING
# define te_log_action(log_level, fmt...) { \
do_crm_log(log_level, __FILE__, __FUNCTION__, fmt); \
fprintf(stderr, fmt); \
fprintf(stderr, "\n"); \
}
#else
# define te_log_action(log_level, fmt...) do_crm_log(log_level, __FILE__, __FUNCTION__, fmt)
#endif
#endif
diff --git a/crm/tengine/utils.c b/crm/tengine/utils.c
index f4be0f4489..f37d641b70 100644
--- a/crm/tengine/utils.c
+++ b/crm/tengine/utils.c
@@ -1,437 +1,437 @@
-/* $Id: utils.c,v 1.36 2005/06/16 12:42:54 andrew Exp $ */
+/* $Id: utils.c,v 1.37 2005/07/03 22:15:49 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <sys/param.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/msg.h>
#include <crm/common/xml.h>
#include <tengine.h>
#include <heartbeat.h>
#include <clplumbing/Gmain_timeout.h>
#include <lrm/lrm_api.h>
extern cib_t *te_cib_conn;
extern int global_transition_timer;
void print_input(const char *prefix, action_t *input, gboolean to_file);
void print_action(const char *prefix, action_t *action, gboolean to_file);
gboolean timer_callback(gpointer data);
void
send_complete(const char *text, crm_data_t *msg,
te_reason_t reason, te_fsa_input_t input)
{
HA_Message *cmd = NULL;
const char *op = CRM_OP_TEABORT;
static te_reason_t last_reason = te_done;
static crm_data_t *last_msg = NULL;
static const char *last_text = NULL;
te_fsa_state_t last_state = te_fsa_state;
te_fsa_state = te_state_matrix[input][te_fsa_state];
if(te_fsa_state == s_abort_pending && num_cib_op_callbacks() == 0) {
te_fsa_state = te_state_matrix[i_cib_complete][te_fsa_state];
}
if(te_fsa_state != s_idle && input != i_cib_complete) {
if(last_msg) {
free_xml(last_msg);
}
last_msg = NULL;
if(msg != NULL) {
last_msg = copy_xml(msg);
}
last_text = text;
last_reason = reason;
crm_info("CIB updates are pending. Delay until they complete.");
return;
} else if(te_fsa_state != s_idle) {
crm_err("Delaying \"%s\" notification until we are idle.",text);
return;
} else if(input == i_cib_complete) {
msg = last_msg;
text = last_text;
reason = last_reason;
}
CRM_DEV_ASSERT(num_cib_op_callbacks() == 0);
switch(reason) {
case te_update:
te_log_action(LOG_DEBUG,
"Transition status: %s by CIB update: %s",
last_state!=s_idle?"Aborted":"Triggered",
text);
if(msg != NULL) {
if(safe_str_eq(crm_element_name(msg),
XML_TAG_CIB)) {
crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, msg);
crm_data_t *generation = create_xml_node(NULL, XML_TAG_CIB);
crm_debug("Cause:"
" full CIB replace/update");
copy_in_properties(generation, msg);
crm_log_xml_debug(generation, "[generation]");
crm_log_xml_debug(status, "[in ]");
free_xml(generation);
} else {
crm_log_xml_debug(msg, "Cause");
}
}
print_state(LOG_DEBUG);
break;
case te_halt:
te_log_action(LOG_INFO,"Transition status: Stopped%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
op = CRM_OP_TECOMPLETE;
break;
case te_abort_confirmed:
te_log_action(LOG_INFO,
"Transition status: Confirmed Stopped%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
op = CRM_OP_TEABORTED;
break;
case te_abort:
te_log_action(LOG_INFO,"Transition status: Stopped%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
break;
case te_done:
te_log_action(LOG_INFO,
"Transition status: Complete%s%s",
text?": ":"", text?text:"");
print_state(LOG_DEBUG);
op = CRM_OP_TECOMPLETE;
break;
case te_timeout:
te_log_action(LOG_ERR,
"Transition status: Timed out after %dms",
transition_timer->timeout);
print_state(LOG_WARNING);
op = CRM_OP_TETIMEOUT;
break;
case te_failed:
te_log_action(LOG_ERR, "Transition status: Aborted by failed action: %s", text);
crm_log_xml_debug(msg, "Cause");
print_state(LOG_WARNING);
break;
}
initialize_graph();
cmd = create_request(
op, NULL, NULL, CRM_SYSTEM_DC, CRM_SYSTEM_TENGINE, NULL);
if(text != NULL) {
ha_msg_add(cmd, "message", text);
}
free_xml(last_msg);
#ifdef TESTING
if(reason == te_done) {
crm_log_message(LOG_INFO, cmd);
} else {
crm_log_message(LOG_ERR, cmd);
}
g_main_quit(mainloop);
return;
#else
send_ipc_message(crm_ch, cmd);
#endif
#if 0
if(is_ipc_empty(crm_ch)
&& is_ipc_empty(te_cib_conn->cmds->channel(te_cib_conn)) ) {
static gboolean mem_needs_init = TRUE;
if(mem_needs_init) {
crm_debug("Reached a stable point:"
" reseting memory usage stats to zero");
crm_zero_mem_stats(NULL);
mem_needs_init = FALSE;
} else {
crm_err("Reached a stable point:"
" checking memory usage");
crm_mem_stats(NULL);
}
}
#endif
}
void
-print_state(int log_level)
+print_state(unsigned int log_level)
{
gboolean first_synapse = TRUE;
if(graph == NULL && log_level > LOG_DEBUG) {
crm_debug("## Empty transition graph ##");
return;
}
slist_iter(
synapse, synapse_t, graph, lpc,
first_synapse = FALSE;
crm_log_maybe(log_level, "Synapse %d %s", synapse->id,
synapse->confirmed?"was confirmed":synapse->complete?"was executed":"is pending");
if(synapse->confirmed == FALSE) {
slist_iter(
action, action_t, synapse->actions, lpc2,
print_action("\t", action, log_level);
);
}
if(synapse->complete == FALSE) {
slist_iter(
input, action_t, synapse->inputs, lpc2,
print_input("\t", input, log_level);
);
}
);
if(first_synapse && log_level > LOG_DEBUG) {
crm_debug("## Empty transition graph ##");
return;
}
}
void
print_input(const char *prefix, action_t *input, int log_level)
{
do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Input %d] %s (%s)",
prefix, input->id,
input->complete?"Satisfied":"Pending",
actiontype2text(input->type));
if(input->complete == FALSE) {
crm_log_xml((unsigned)log_level, "\t Raw input", input->xml);
}
}
void
print_action(const char *prefix, action_t *action, int log_level)
{
do_crm_log(log_level, __FILE__, __FUNCTION__, "%s[Action %d] %s (%s fail)",
prefix, action->id, action->complete?"Completed":
action->invoked?"In-flight":"Pending",
action->can_fail?"can":"cannot");
switch(action->type) {
case action_type_pseudo:
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\tPseudo Op: %s", prefix,
crm_element_value(
action->xml, XML_LRM_ATTR_TASK));
break;
case action_type_rsc:
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\tResource Op: %s/%s on %s", prefix,
crm_element_value(
action->xml, XML_LRM_ATTR_RSCID),
crm_element_value(
action->xml, XML_LRM_ATTR_TASK),
crm_element_value(
action->xml, XML_LRM_ATTR_TARGET));
break;
case action_type_crm:
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\tCRM Op: %s on %s", prefix,
crm_element_value(
action->xml, XML_LRM_ATTR_TASK),
crm_element_value(
action->xml, XML_LRM_ATTR_TARGET));
break;
}
if(action->timeout > 0 || action->timer->source_id > 0) {
do_crm_log(log_level, __FILE__, __FUNCTION__,
"%s\ttimeout=%d, timer=%d", prefix,
action->timeout, action->timer->source_id);
}
if(action->complete == FALSE) {
crm_log_xml(LOG_DEBUG_2, "\tRaw action", action->xml);
}
}
gboolean
timer_callback(gpointer data)
{
te_timer_t *timer = NULL;
if(data == NULL) {
crm_err("Timer popped with no data");
return FALSE;
}
timer = (te_timer_t*)data;
if(timer->source_id > 0) {
g_source_remove(timer->source_id);
}
timer->source_id = -1;
crm_err("Timer popped in state=%d", te_fsa_state);
if(te_fsa_state != s_in_transition) {
crm_debug("Ignoring timeout while not in transition");
return TRUE;
} else if(timer->reason == timeout_timeout) {
/* global timeout - abort the transition */
crm_warn("Transition timeout reached..."
" marking transition complete.");
crm_warn("Some actions may not have been executed.");
send_complete(XML_ATTR_TIMEOUT, NULL, te_timeout, i_cancel);
return TRUE;
} else if(timer->action == NULL) {
crm_err("Action not present!");
return FALSE;
} else if(timer->reason == timeout_action_warn) {
crm_warn("Action %d is taking more than 2x its timeout (%d)",
timer->action->id, timer->action->timeout);
crm_log_xml_debug(timer->action->xml, "Slow action");
return TRUE;
} else {
/* fail the action
* - which may or may not abort the transition
*/
/* TODO: send a cancel notice to the LRM */
/* TODO: use the ack from above to update the CIB */
return cib_action_update(timer->action, LRM_OP_TIMEOUT);
}
}
gboolean
start_te_timer(te_timer_t *timer)
{
if(((int)timer->source_id) < 0 && timer->timeout > 0) {
timer->source_id = Gmain_timeout_add(
timer->timeout, timer_callback, (void*)timer);
return TRUE;
} else if(timer->timeout < 0) {
crm_err("Tried to start timer with -ve period");
} else {
crm_debug_3("#!!#!!# Timer already running (%d)",
timer->source_id);
}
return FALSE;
}
gboolean
stop_te_timer(te_timer_t *timer)
{
if(timer == NULL) {
return FALSE;
}
if(((int)timer->source_id) > 0) {
g_source_remove(timer->source_id);
timer->source_id = -2;
} else {
return FALSE;
}
return TRUE;
}
const char *
actiontype2text(action_type_e type)
{
switch(type) {
case action_type_pseudo:
return "pseduo";
case action_type_rsc:
return "rsc";
case action_type_crm:
return "crm";
}
return "<unknown>";
}
const char *
get_rsc_state(const char *task, op_status_t status)
{
if(safe_str_eq(CRMD_ACTION_START, task)) {
if(status == LRM_OP_PENDING) {
return CRMD_ACTION_START_PENDING;
} else if(status == LRM_OP_DONE) {
return CRMD_ACTION_STARTED;
} else {
return CRMD_ACTION_START_FAIL;
}
} else if(safe_str_eq(CRMD_ACTION_STOP, task)) {
if(status == LRM_OP_PENDING) {
return CRMD_ACTION_STOP_PENDING;
} else if(status == LRM_OP_DONE) {
return CRMD_ACTION_STOPPED;
} else {
return CRMD_ACTION_STOP_FAIL;
}
} else {
if(safe_str_eq(CRMD_ACTION_MON, task)) {
if(status == LRM_OP_PENDING) {
return CRMD_ACTION_MON_PENDING;
} else if(status == LRM_OP_DONE) {
return CRMD_ACTION_MON_OK;
} else {
return CRMD_ACTION_MON_FAIL;
}
} else {
const char *rsc_state = NULL;
if(status == LRM_OP_PENDING) {
rsc_state = CRMD_ACTION_GENERIC_PENDING;
} else if(status == LRM_OP_DONE) {
rsc_state = CRMD_ACTION_GENERIC_OK;
} else {
rsc_state = CRMD_ACTION_GENERIC_FAIL;
}
crm_warn("Using status \"%s\" for op \"%s\"..."
" this is still in the experimental stage.",
rsc_state, task);
return rsc_state;
}
}
}
diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h
index def8882fee..429219b0ca 100644
--- a/include/crm/common/xml.h
+++ b/include/crm/common/xml.h
@@ -1,280 +1,280 @@
-/* $Id: xml.h,v 1.26 2005/06/16 12:44:31 andrew Exp $ */
+/* $Id: xml.h,v 1.27 2005/07/03 22:15:50 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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
*/
#ifndef CRM_COMMON_XML__H
#define CRM_COMMON_XML__H
#include <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <ha_msg.h>
#include <clplumbing/cl_log.h>
/* #define USE_LIBXML 1 */
#define XML_PARANOIA_CHECKS 1
#ifdef USE_LIBXML
# include <libxml/tree.h>
typedef xmlNode crm_data_t;
#else
typedef struct ha_msg crm_data_t;
#endif
extern gboolean add_message_xml(
HA_Message *msg, const char *field, const crm_data_t *xml);
extern crm_data_t *get_message_xml(const HA_Message *msg, const char *field);
/*
* Replacement function for xmlCopyPropList which at the very least,
* doesnt work the way *I* would expect it to.
*
* Copy all the attributes/properties from src into target.
*
* Not recursive, does not return anything.
*
*/
extern void copy_in_properties(crm_data_t *target, const crm_data_t *src);
/*
* Find a child named search_path[i] at level i in the XML fragment where i=0
* is an immediate child of <i>root</i>.
*
* Terminate with success if i == len, or search_path[i] == NULL.
*
* On success, returns the sub-fragment described by search_path.
* On failure, returns NULL.
*/
extern crm_data_t *find_xml_node_nested(
crm_data_t *root, const char **search_path, int len);
/*
* Find a child named search_path[i] at level i in the XML fragment where i=0
* is an immediate child of <i>root</i>.
*
* Once the last child specified by node_path is found, find the value
* of attr_name.
*
* If <i>error<i> is set to TRUE, then it is an error for the attribute not
* to be found and the function will log accordingly.
*
* On success, returns the value of attr_name.
* On failure, returns NULL.
*/
extern const char *get_xml_attr_nested(crm_data_t *parent,
const char **node_path, int length,
const char *attr_name, gboolean error);
/*
* Free the XML "stuff" associated with a_node
*
* If a_node is part of another XML blob, barf.
* (Should be using free_xml_from_parent)
*
* Otherwise, free everything recursivly
*
* Wont barf on NULL.
*
*/
extern void free_xml_fn(crm_data_t *a_node);
#if 1
# define free_xml(xml_obj) free_xml_fn(xml_obj); xml_obj = NULL
#else
# define free_xml(xml_obj) xml_obj = NULL
#endif
void free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node);
#define zap_xml_from_parent(parent, xml_obj) free_xml_from_parent(parent, xml_obj); xml_obj = NULL
/*
* Create a node named "name" as a child of "parent"
* If parent is NULL, creates an unconnected node.
*
* Returns the created node
*
*/
extern crm_data_t *create_xml_node(crm_data_t *parent, const char *name);
/*
* Make a copy of name and value and use the copied memory to create
* an attribute for node.
*
* If node, name or value are NULL, nothing is done.
*
* If name or value are an empty string, nothing is done.
*
* Returns FALSE on failure and TRUE on success.
*
*/
extern const char *crm_xml_add(
crm_data_t *node, const char *name, const char *value);
extern const char *crm_xml_add_int(
crm_data_t* node, const char *name, int value);
/*
* Unlink the node and set its doc pointer to NULL so free_xml()
* will act appropriately
*/
extern void unlink_xml_node(crm_data_t *node);
/*
* Set a timestamp attribute on a_node
*/
extern void set_node_tstamp(crm_data_t *a_node);
/*
* Returns a deep copy of src_node
*
*/
extern crm_data_t *copy_xml(const crm_data_t *src_node);
/*
* Add a copy of xml_node to new_parent
*/
extern crm_data_t *add_node_copy(
crm_data_t *new_parent, const crm_data_t *xml_node);
/*
* XML I/O Functions
*
* Whitespace between tags is discarded.
*/
extern crm_data_t *file2xml(FILE *input);
extern crm_data_t *stdin2xml(void);
extern crm_data_t *string2xml(const char *input);
extern int write_xml_file(crm_data_t *xml_node, const char *filename);
extern char *dump_xml_formatted(const crm_data_t *msg);
extern char *dump_xml_unformatted(const crm_data_t *msg);
extern void print_xml_formatted(
int log_level, const char *function,
const crm_data_t *an_xml_node, const char *text);
/*
* Diff related Functions
*/
extern crm_data_t *diff_xml_object(
crm_data_t *left, crm_data_t *right, gboolean suppress);
-extern void log_xml_diff(int log_level, crm_data_t *diff, const char *function);
+extern void log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function);
extern gboolean apply_xml_diff(
crm_data_t *old, crm_data_t *diff, crm_data_t **new);
/*
* Searching & Modifying
*/
extern crm_data_t *find_xml_node(
crm_data_t *cib, const char * node_path, gboolean must_find);
extern crm_data_t *find_entity(
crm_data_t *parent, const char *node_name, const char *id);
extern crm_data_t *subtract_xml_object(
crm_data_t *left, crm_data_t *right, gboolean suppress);
extern int add_xml_object(
crm_data_t *parent, crm_data_t *target, const crm_data_t *update);
extern void xml_remove_prop(crm_data_t *obj, const char *name);
extern void crm_set_element_parent(crm_data_t *data, crm_data_t *parent);
extern gboolean delete_xml_child(
crm_data_t *parent, crm_data_t *child, crm_data_t *to_delete);
/*
*
*/
extern const char *crm_element_value(const crm_data_t *data, const char *name);
extern char *crm_element_value_copy(const crm_data_t *data, const char *name);
extern const char *crm_element_name(const crm_data_t *data);
extern void crm_validate_data(const crm_data_t *root);
extern void crm_update_parents(crm_data_t *root);
extern gboolean xml_has_children(crm_data_t *root);
# define xmlGetNodePath(data) crm_element_value(data, XML_ATTR_TAGNAME)
# define xml_child_iter(parent, child, filter, loop_code) \
if(parent != NULL) { \
int __counter = 0; \
crm_data_t *child = NULL; \
crm_validate_data(parent); \
for (__counter = 0; __counter < parent->nfields; __counter++) { \
if(parent->types[__counter] != FT_STRUCT) { \
continue; \
} \
child = parent->values[__counter]; \
if(child == NULL) { \
crm_debug_4("Skipping %s == NULL", \
parent->names[__counter]); \
} else if(filter == NULL \
|| safe_str_eq(filter, parent->names[__counter])) { \
loop_code; \
} else { \
crm_debug_4("Skipping <%s../>", \
parent->names[__counter]); \
} \
} \
} else { \
crm_debug_4("Parent of loop was NULL"); \
}
#define xml_prop_iter(parent, prop_name, prop_value, code) if(parent != NULL) { \
const char *prop_name = NULL; \
const char *prop_value = NULL; \
int __counter = 0; \
crm_validate_data(parent); \
crm_debug_5("Searching %d fields", parent->nfields); \
for (__counter = 0; __counter < parent->nfields; __counter++) { \
crm_debug_5("Searching field %d", __counter); \
if(parent->types[__counter] != FT_STRING) { \
continue; \
} else if(safe_str_eq(parent->names[__counter], F_XML_TAGNAME)) { \
continue; \
} else if(safe_str_eq(parent->names[__counter], F_XML_PARENT)) { \
continue; \
} \
prop_name = parent->names[__counter]; \
prop_value = parent->values[__counter]; \
code; \
} \
} else { \
crm_debug_4("Parent of loop was NULL"); \
}
#endif
diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c
index 5f8f54e403..bb463c9c34 100644
--- a/lib/crm/common/xml.c
+++ b/lib/crm/common/xml.c
@@ -1,1791 +1,1791 @@
-/* $Id: xml.c,v 1.19 2005/06/30 14:13:07 andrew Exp $ */
+/* $Id: xml.c,v 1.20 2005/07/03 22:15:50 alan Exp $ */
/*
* Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
*
* 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 <portability.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <clplumbing/ipc.h>
#include <clplumbing/cl_log.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/dmalloc_wrapper.h>
void dump_array(
int log_level, const char *message, const char **array, int depth);
int print_spaces(char *buffer, int spaces);
int log_data_element(const char *function, const char *prefix, int log_level,
int depth, const crm_data_t *data, gboolean formatted);
int dump_data_element(
int depth, char **buffer, const crm_data_t *data, gboolean formatted);
crm_data_t *parse_xml(const char *input, int *offset);
int get_tag_name(const char *input);
int get_attr_name(const char *input);
int get_attr_value(const char *input);
gboolean can_prune_leaf(crm_data_t *xml_node);
void diff_filter_context(int context, int upper_bound, int lower_bound,
crm_data_t *xml_node, crm_data_t *parent);
int in_upper_context(int depth, int context, crm_data_t *xml_node);
crm_data_t *
find_xml_node(crm_data_t *root, const char * search_path, gboolean must_find)
{
if(must_find || root != NULL) {
crm_validate_data(root);
}
if(search_path == NULL) {
crm_warn("Will never find <NULL>");
return NULL;
}
xml_child_iter(
root, a_child, search_path,
/* crm_debug_5("returning node (%s).", xmlGetNodePath(a_child)); */
crm_log_xml_debug_5(a_child, "contents\t%s");
crm_log_xml_debug_5(root, "found in\t%s");
crm_validate_data(a_child);
return a_child;
);
if(must_find) {
crm_warn("Could not find %s in %s.", search_path, xmlGetNodePath(root));
} else if(root != NULL) {
crm_debug_3("Could not find %s in %s.", search_path, xmlGetNodePath(root));
} else {
crm_debug_3("Could not find %s in <NULL>.", search_path);
}
return NULL;
}
crm_data_t*
find_xml_node_nested(crm_data_t *root, const char **search_path, int len)
{
int j;
gboolean is_found = TRUE;
crm_data_t *match = NULL;
crm_data_t *lastMatch = root;
crm_validate_data(root);
if(search_path == NULL || search_path[0] == NULL) {
crm_warn("Will never find NULL");
return NULL;
}
dump_array(LOG_DEBUG_5, "Looking for.", search_path, len);
for (j=0; j < len; ++j) {
if (search_path[j] == NULL) {
/* a NULL also means stop searching */
break;
}
match = find_xml_node(lastMatch, search_path[j], FALSE);
if(match == NULL) {
is_found = FALSE;
break;
} else {
lastMatch = match;
}
}
if (is_found) {
crm_debug_5("returning node (%s).",
xmlGetNodePath(lastMatch));
crm_log_xml_debug_5(lastMatch, "found\t%s");
crm_log_xml_debug_5(root, "in \t%s");
crm_validate_data(lastMatch);
return lastMatch;
}
dump_array(LOG_DEBUG_2,
"Could not find the full path to the node you specified.",
search_path, len);
crm_debug_2("Closest point was node (%s) starting from %s.",
xmlGetNodePath(lastMatch), crm_element_name(root));
return NULL;
}
const char *
get_xml_attr_nested(crm_data_t *parent,
const char **node_path, int length,
const char *attr_name, gboolean error)
{
const char *attr_value = NULL;
crm_data_t *attr_parent = NULL;
if(error || parent != NULL) {
crm_validate_data(parent);
}
if(parent == NULL) {
crm_debug_3("Can not find attribute %s in NULL parent",attr_name);
return NULL;
}
if(attr_name == NULL || strlen(attr_name) == 0) {
crm_err("Can not find attribute with no name in %s",
xmlGetNodePath(parent));
return NULL;
}
if(length == 0) {
attr_parent = parent;
} else {
attr_parent = find_xml_node_nested(parent, node_path, length);
if(attr_parent == NULL && error) {
crm_err("No node at the path you specified.");
return NULL;
}
}
attr_value = crm_element_value(attr_parent, attr_name);
if((attr_value == NULL || strlen(attr_value) == 0) && error) {
crm_err("No value present for %s at %s",
attr_name, xmlGetNodePath(attr_parent));
return NULL;
}
return attr_value;
}
crm_data_t*
find_entity(crm_data_t *parent, const char *node_name, const char *id)
{
crm_validate_data(parent);
xml_child_iter(
parent, a_child, node_name,
if(id == NULL
|| safe_str_eq(id,crm_element_value(a_child,XML_ATTR_ID))){
crm_debug_4("returning node (%s).",
xmlGetNodePath(a_child));
return a_child;
}
);
crm_debug_3("node <%s id=%s> not found in %s.",
node_name, id, xmlGetNodePath(parent));
return NULL;
}
void
copy_in_properties(crm_data_t* target, const crm_data_t *src)
{
crm_validate_data(src);
crm_validate_data(target);
if(src == NULL) {
crm_warn("No node to copy properties from");
} else if (target == NULL) {
crm_err("No node to copy properties into");
} else {
xml_prop_iter(
src, local_prop_name, local_prop_value,
crm_xml_add(target, local_prop_name, local_prop_value);
);
crm_validate_data(target);
}
return;
}
crm_data_t*
add_node_copy(crm_data_t *new_parent, const crm_data_t *xml_node)
{
crm_data_t *node_copy = NULL;
crm_validate_data(new_parent);
crm_validate_data(xml_node);
if(xml_node != NULL && new_parent != NULL) {
const char *name = crm_element_name(xml_node);
CRM_DEV_ASSERT(
HA_OK == ha_msg_addstruct(new_parent, name, xml_node));
node_copy = find_entity(
new_parent, crm_element_name(xml_node), ID(xml_node));
crm_validate_data(node_copy);
crm_update_parents(new_parent);
crm_validate_data(new_parent);
} else if(xml_node == NULL) {
crm_err("Could not add copy of NULL node");
} else {
crm_err("Could not add copy of node to NULL parent");
}
crm_validate_data(node_copy);
return node_copy;
}
const char *
crm_xml_add(crm_data_t* node, const char *name, const char *value)
{
const char *parent_name = NULL;
if(node != NULL) {
parent_name = crm_element_name(node);
}
crm_debug_5("[%s] Setting %s to %s", crm_str(parent_name), name, value);
if (name == NULL || strlen(name) <= 0) {
} else if(node == NULL) {
} else if(parent_name == NULL && strcmp(name, F_XML_TAGNAME) != 0) {
} else if (value == NULL || strlen(value) <= 0) {
xml_remove_prop(node, name);
return NULL;
} else {
crm_validate_data(node);
ha_msg_mod(node, name, value);
return crm_element_value(node, name);
}
return NULL;
}
const char *
crm_xml_add_int(crm_data_t* node, const char *name, int value)
{
const char *parent_name = NULL;
if(node != NULL) {
parent_name = crm_element_name(node);
}
crm_debug_5("[%s] Setting %s to %d", crm_str(parent_name), name, value);
if (name == NULL || strlen(name) <= 0) {
} else if(node == NULL) {
} else if(parent_name == NULL && strcmp(name, F_XML_TAGNAME) != 0) {
} else {
crm_validate_data(node);
ha_msg_mod_int(node, name, value);
return crm_element_value(node, name);
}
return NULL;
}
crm_data_t*
create_xml_node(crm_data_t *parent, const char *name)
{
const char *local_name = NULL;
const char *parent_name = NULL;
crm_data_t *ret_value = NULL;
if (name == NULL || strlen(name) < 1) {
ret_value = NULL;
} else {
local_name = name;
ret_value = ha_msg_new(1);
CRM_DEV_ASSERT(ret_value != NULL);
crm_xml_add(ret_value, F_XML_TAGNAME, name);
crm_validate_data(ret_value);
if(parent) {
crm_validate_data(parent);
parent_name = crm_element_name(parent);
crm_debug_5("Attaching %s to parent %s",
local_name, parent_name);
CRM_DEV_ASSERT(HA_OK == ha_msg_addstruct(
parent, name, ret_value));
crm_msg_del(ret_value);
crm_update_parents(parent);
crm_validate_data(parent);
ret_value = parent->values[parent->nfields-1];
crm_validate_data(ret_value);
}
}
crm_debug_5("Created node [%s [%s]]",
crm_str(parent_name), crm_str(local_name));
/* set_node_tstamp(ret_value); */
return ret_value;
}
void
free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node)
{
CRM_DEV_ASSERT(parent != NULL);
if(parent == NULL) {
return;
} else if(a_node == NULL) {
return;
}
crm_validate_data(parent);
cl_msg_remove_value(parent, a_node);
crm_validate_data(parent);
}
void
free_xml_fn(crm_data_t *a_node)
{
if(a_node == NULL) {
; /* nothing to do */
} else {
int has_parent = 0;
crm_validate_data(a_node);
ha_msg_value_int(a_node, F_XML_PARENT, &has_parent);
/* there is no way in hell we should be deleting anything
* with a parent and without the parent knowning
*/
CRM_DEV_ASSERT(has_parent == 0);
if(has_parent == 0) {
crm_validate_data(a_node);
crm_msg_del(a_node);
}
}
return;
}
void
set_node_tstamp(crm_data_t *a_node)
{
#if 0
char *since_epoch = NULL;
time_t a_time = time(NULL);
crm_validate_data(a_node);
if(a_time == (time_t)-1) {
cl_perror("set_node_tstamp(): Invalid time returned");
return;
}
crm_malloc0(since_epoch, 128*(sizeof(char)));
if(since_epoch != NULL) {
sprintf(since_epoch, "%ld", (unsigned long)a_time);
ha_msg_mod(a_node, XML_ATTR_TSTAMP, since_epoch);
crm_validate_data(a_node);
crm_free(since_epoch);
}
#endif
}
crm_data_t*
copy_xml(const crm_data_t *src_node)
{
crm_data_t *new_xml = NULL;
CRM_DEV_ASSERT(src_node != NULL);
CRM_DEV_ASSERT(crm_element_name(src_node) != NULL);
if(src_node == NULL) {
crm_warn("Attempt to dup NULL XML");
return NULL;
} else if(crm_element_name(src_node) == NULL) {
crm_log_xml_err(src_node, "Attempt to dup XML with no name");
return NULL;
}
crm_validate_data(src_node);
new_xml = ha_msg_copy(src_node);
crm_set_element_parent(new_xml, NULL);
crm_update_parents(new_xml);
crm_validate_data(new_xml);
return new_xml;
}
crm_data_t*
string2xml(const char *input)
{
crm_data_t *output = parse_xml(input, NULL);
if(output != NULL) {
crm_update_parents(output);
crm_validate_data(output);
}
return output;
}
crm_data_t *
stdin2xml(void)
{
int lpc = 0;
int MAX_XML_BUFFER = 20000;
int ch = 0;
gboolean more = TRUE;
gboolean inTag = FALSE;
FILE *input = stdin;
char *xml_buffer = NULL;
crm_data_t *xml_obj = NULL;
crm_malloc0(xml_buffer, sizeof(char)*(MAX_XML_BUFFER+1));
while (more && lpc < MAX_XML_BUFFER) {
ch = fgetc(input);
/* crm_debug_3("Got [%c]", ch); */
switch(ch) {
case EOF:
case 0:
ch = 0;
more = FALSE;
xml_buffer[lpc++] = ch;
break;
case '>':
case '<':
inTag = TRUE;
if(ch == '>') { inTag = FALSE; }
xml_buffer[lpc++] = ch;
break;
case '\n':
case '\t':
case ' ':
ch = ' ';
if(inTag) {
xml_buffer[lpc++] = ch;
}
break;
default:
xml_buffer[lpc++] = ch;
break;
}
}
xml_buffer[MAX_XML_BUFFER] = 0;
xml_obj = string2xml(xml_buffer);
crm_free(xml_buffer);
crm_log_xml_debug_3(xml_obj, "Created fragment");
return xml_obj;
}
crm_data_t*
file2xml(FILE *input)
{
char *buffer = NULL;
crm_data_t *new_obj = NULL;
int start = 0, length = 0, read_len = 0;
/* see how big the file is */
start = ftell(input);
fseek(input, 0L, SEEK_END);
length = ftell(input);
fseek(input, 0L, start);
if(start != ftell(input)) {
crm_err("fseek not behaving");
return NULL;
}
crm_debug_3("Reading %d bytes from file", length);
crm_malloc0(buffer, sizeof(char) * (length+1));
read_len = fread(buffer, sizeof(char), length, input);
if(read_len != length) {
crm_err("Calculated and read bytes differ: %d vs. %d",
length, read_len);
} else if(length > 0) {
new_obj = string2xml(buffer);
} else {
crm_warn("File contained no XML");
}
crm_free(buffer);
return new_obj;
}
void
dump_array(int log_level, const char *message, const char **array, int depth)
{
int j;
if(message != NULL) {
do_crm_log(log_level, __FILE__, __FUNCTION__, "%s", message);
}
do_crm_log(log_level, __FILE__, __FUNCTION__, "Contents of the array:");
if(array == NULL || array[0] == NULL || depth == 0) {
do_crm_log(log_level, __FILE__, __FUNCTION__, "\t<empty>");
return;
}
for (j=0; j < depth && array[j] != NULL; j++) {
if (array[j] == NULL) { break; }
do_crm_log(log_level, __FILE__, __FUNCTION__, "\t--> (%s).", array[j]);
}
}
int
write_xml_file(crm_data_t *xml_node, const char *filename)
{
int res = 0;
char *now_str = NULL;
time_t now;
crm_debug_3("Writing XML out to %s", filename);
crm_validate_data(xml_node);
if (xml_node == NULL) {
return -1;
}
crm_validate_data(xml_node);
crm_log_xml_debug_4(xml_node, "Writing out");
crm_validate_data(xml_node);
now = time(NULL);
now_str = ctime(&now);
now_str[24] = EOS; /* replace the newline */
crm_xml_add(xml_node, "last_written", now_str);
crm_validate_data(xml_node);
{
FILE *file_output_strm = fopen(filename, "w");
char *buffer = dump_xml_formatted(xml_node);
CRM_DEV_ASSERT(buffer != NULL && strlen(buffer) > 0);
if(file_output_strm == NULL) {
res = -1;
crm_err("Cannot write to %s", filename);
} else if(buffer != NULL && strlen(buffer) > 0) {
res = fprintf(file_output_strm, "%s", buffer);
}
if(file_output_strm != NULL) {
fflush(file_output_strm);
fclose(file_output_strm);
}
crm_free(buffer);
}
crm_debug_3("Saved %d bytes to the Cib as XML", res);
return res;
}
void
print_xml_formatted(int log_level, const char *function,
const crm_data_t *msg, const char *text)
{
if(msg == NULL) {
do_crm_log(log_level,NULL,function, "%s: NULL", crm_str(text));
return;
}
crm_validate_data(msg);
do_crm_log(log_level, NULL, function, "%s:", crm_str(text));
log_data_element(function, NULL, log_level, 0, msg, TRUE);
return;
}
crm_data_t *
get_message_xml(const HA_Message *msg, const char *field)
{
crm_data_t *xml_node = NULL;
crm_data_t *tmp_node = NULL;
crm_validate_data(msg);
tmp_node = cl_get_struct(msg, field);
if(tmp_node != NULL) {
xml_node = copy_xml(tmp_node);
}
return xml_node;
}
gboolean
add_message_xml(HA_Message *msg, const char *field, const crm_data_t *xml)
{
crm_validate_data(xml);
crm_validate_data(msg);
ha_msg_addstruct(msg, field, xml);
crm_update_parents(msg);
return TRUE;
}
char *
dump_xml_formatted(const crm_data_t *an_xml_node)
{
char *buffer = NULL;
char *mutable_ptr = NULL;
#if 0
crm_malloc0(buffer, 3*get_stringlen(an_xml_node));
#else
crm_malloc0(buffer, sizeof(char)*60000);
#endif
mutable_ptr = buffer;
crm_validate_data(an_xml_node);
CRM_DEV_ASSERT(dump_data_element(
0, &mutable_ptr, an_xml_node, TRUE) >= 0);
if(crm_assert_failed) {
crm_crit("Could not dump the whole message");
}
crm_debug_4("Dumped: %s", buffer);
return buffer;
}
char *
dump_xml_unformatted(const crm_data_t *an_xml_node)
{
char *buffer = NULL;
char *mutable_ptr = NULL;
#if 0
crm_malloc0(buffer, 2*get_stringlen(an_xml_node));
#else
crm_malloc0(buffer, sizeof(char)*20000);
#endif
mutable_ptr = buffer;
crm_validate_data(an_xml_node);
CRM_DEV_ASSERT(dump_data_element(
0, &mutable_ptr, an_xml_node, TRUE) >= 0);
if(crm_assert_failed) {
crm_crit("Could not dump the whole message");
}
crm_debug_4("Dumped: %s", buffer);
return buffer;
}
#define update_buffer_head(buffer, len) if(len < 0) { \
(*buffer) = EOS; return -1; \
} else { \
buffer += len; \
}
int
print_spaces(char *buffer, int depth)
{
int lpc = 0;
int spaces = 2*depth;
/* <= so that we always print 1 space - prevents problems with syslog */
for(lpc = 0; lpc <= spaces; lpc++) {
if(sprintf(buffer, "%c", ' ') < 1) {
return -1;
}
buffer += 1;
}
return lpc;
}
int
log_data_element(
const char *function, const char *prefix, int log_level, int depth,
const crm_data_t *data, gboolean formatted)
{
int printed = 0;
int child_result = 0;
int has_children = 0;
char print_buffer[1000];
char *buffer = print_buffer;
const char *name = crm_element_name(data);
crm_debug_5("Dumping %s...", name);
crm_validate_data(data);
if(data == NULL) {
crm_warn("No data to dump as XML");
return 0;
} else if(name == NULL && depth == 0) {
xml_child_iter(
data, a_child, NULL,
child_result = log_data_element(
function, prefix, log_level, depth, a_child, formatted);
if(child_result < 0) {
return child_result;
}
);
return 0;
} else if(name == NULL) {
crm_err("Cannot dump NULL element at depth %d", depth);
return -1;
}
if(formatted) {
printed = print_spaces(buffer, depth);
update_buffer_head(buffer, printed);
}
printed = sprintf(buffer, "<%s", name);
update_buffer_head(buffer, printed);
xml_prop_iter(
data, prop_name, prop_value,
if(safe_str_eq(F_XML_TAGNAME, prop_name)) {
continue;
} else if(safe_str_eq(F_XML_PARENT, prop_name)) {
continue;
}
crm_debug_5("Dumping <%s %s=\"%s\"...",
name, prop_name, prop_value);
printed = sprintf(buffer, " %s=\"%s\"", prop_name, prop_value);
update_buffer_head(buffer, printed);
);
xml_child_iter(
data, child, NULL,
if(child != NULL) {
has_children++;
break;
}
);
printed = sprintf(buffer, "%s>", has_children==0?"/":"");
update_buffer_head(buffer, printed);
do_crm_log(log_level, function, NULL, "%s%s",
prefix?prefix:"", print_buffer);
buffer = print_buffer;
if(has_children == 0) {
return 0;
}
xml_child_iter(
data, a_child, NULL,
child_result = log_data_element(
function, prefix, log_level, depth+1, a_child, formatted);
if(child_result < 0) { return -1; }
);
if(formatted) {
printed = print_spaces(buffer, depth);
update_buffer_head(buffer, printed);
}
do_crm_log(log_level, function, NULL, "%s%s</%s>",
prefix?prefix:"", print_buffer, name);
crm_debug_5("Dumped %s...", name);
return has_children;
}
int
dump_data_element(
int depth, char **buffer, const crm_data_t *data, gboolean formatted)
{
int printed = 0;
int child_result = 0;
int has_children = 0;
const char *name = crm_element_name(data);
crm_debug_5("Dumping %s...", name);
crm_validate_data(data);
if(buffer == NULL || *buffer == NULL) {
crm_err("No buffer supplied to dump XML into");
return -1;
} else if(data == NULL) {
crm_warn("No data to dump as XML");
(*buffer)[0] = EOS;
return 0;
} else if(name == NULL && depth == 0) {
xml_child_iter(
data, a_child, NULL,
child_result = dump_data_element(
depth, buffer, a_child, formatted);
if(child_result < 0) {
return child_result;
}
);
return 0;
} else if(name == NULL) {
crm_err("Cannot dump NULL element at depth %d", depth);
return -1;
}
if(formatted) {
printed = print_spaces(*buffer, depth);
update_buffer_head(*buffer, printed);
}
printed = sprintf(*buffer, "<%s", name);
update_buffer_head(*buffer, printed);
xml_prop_iter(data, prop_name, prop_value,
if(safe_str_eq(F_XML_TAGNAME, prop_name)) {
continue;
} else if(safe_str_eq(F_XML_PARENT, prop_name)) {
continue;
}
crm_debug_5("Dumping <%s %s=\"%s\"...",
name, prop_name, prop_value);
printed = sprintf(*buffer, " %s=\"%s\"", prop_name, prop_value);
update_buffer_head(*buffer, printed);
);
xml_child_iter(
data, child, NULL,
if(child != NULL) {
has_children++;
break;
}
);
printed = sprintf(*buffer, "%s>%s",
has_children==0?"/":"", formatted?"\n":"");
update_buffer_head(*buffer, printed);
if(has_children == 0) {
return 0;
}
xml_child_iter(
data, child, NULL,
child_result = dump_data_element(
depth+1, buffer, child, formatted);
if(child_result < 0) { return -1; }
);
if(formatted) {
printed = print_spaces(*buffer, depth);
update_buffer_head(*buffer, printed);
}
printed = sprintf(*buffer, "</%s>%s", name, formatted?"\n":"");
update_buffer_head(*buffer, printed);
crm_debug_5("Dumped %s...", name);
return has_children;
}
gboolean
xml_has_children(crm_data_t *xml_root)
{
crm_validate_data(xml_root);
xml_child_iter(
xml_root, a_child, NULL,
return TRUE;
);
return FALSE;
}
void
crm_validate_data(const crm_data_t *xml_root)
{
#ifndef XML_PARANOIA_CHECKS
CRM_DEV_ASSERT(xml_root != NULL);
#else
int lpc = 0;
CRM_ASSERT(xml_root != NULL);
CRM_ASSERT(crm_is_allocated(xml_root) == 1);
CRM_ASSERT(xml_root->nfields < 500);
for (lpc = 0; lpc < xml_root->nfields; lpc++) {
void *child = xml_root->values[lpc];
CRM_ASSERT(crm_is_allocated(xml_root->names[lpc]) == 1);
if(child == NULL) {
} else if(xml_root->types[lpc] == FT_STRUCT) {
crm_validate_data(child);
} else if(xml_root->types[lpc] == FT_STRING) {
CRM_ASSERT(crm_is_allocated(child) == 1);
/* } else { */
/* CRM_DEV_ASSERT(FALSE); */
}
}
#endif
}
void
crm_set_element_parent(crm_data_t *data, crm_data_t *parent)
{
crm_validate_data(data);
if(parent != NULL) {
ha_msg_mod_int(data, F_XML_PARENT, 1);
} else {
ha_msg_mod_int(data, F_XML_PARENT, 0);
}
}
const char *
crm_element_value(const crm_data_t *data, const char *name)
{
const char *value = NULL;
crm_validate_data(data);
value = cl_get_string(data, name);
if(value != NULL) {
CRM_DEV_ASSERT(crm_is_allocated(value) == 1);
}
return value;
}
char *
crm_element_value_copy(const crm_data_t *data, const char *name)
{
const char *value = NULL;
char *value_copy = NULL;
crm_validate_data(data);
value = cl_get_string(data, name);
if(value != NULL) {
CRM_DEV_ASSERT(crm_is_allocated(value) == 1);
}
CRM_DEV_ASSERT(value != NULL);
if(value != NULL) {
value_copy = crm_strdup(value);
}
return value_copy;
}
const char *
crm_element_name(const crm_data_t *data)
{
crm_validate_data(data);
return cl_get_string(data, F_XML_TAGNAME);
}
void
xml_remove_prop(crm_data_t *obj, const char *name)
{
if(crm_element_value(obj, name) != NULL) {
cl_msg_remove(obj, name);
}
}
void
crm_update_parents(crm_data_t *xml_root)
{
crm_validate_data(xml_root);
xml_child_iter(
xml_root, a_child, NULL,
crm_set_element_parent(a_child, xml_root);
crm_update_parents(a_child);
);
}
int
get_tag_name(const char *input)
{
int lpc = 0;
char ch = 0;
const char *error = NULL;
gboolean do_special = FALSE;
for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c [%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '?':
if(lpc == 0) {
/* weird xml tag that we dont care about */
do_special = TRUE;
} else {
return lpc;
}
break;
case '/':
case '>':
case '\t':
case '\n':
case ' ':
if(!do_special) {
return lpc;
}
break;
default:
if(do_special) {
} else if('a' <= ch && ch <= 'z') {
} else if('A' <= ch && ch <= 'Z') {
} else if(ch == '_') {
} else if(ch == '-') {
} else {
error = "bad character, not in [a-zA-Z_-]";
}
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
int
get_attr_name(const char *input)
{
int lpc = 0;
char ch = 0;
const char *error = NULL;
for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c[%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '\t':
case '\n':
case ' ':
error = "unexpected whitespace";
break;
case '=':
return lpc;
default:
if('a' <= ch && ch <= 'z') {
} else if('A' <= ch && ch <= 'Z') {
} else if(ch == '_') {
} else if(ch == '-') {
} else {
error = "bad character, not in [a-zA-Z_-]";
}
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
int
get_attr_value(const char *input)
{
int lpc = 0;
char ch = 0;
const char *error = NULL;
for(lpc = 0; error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c [%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '\\':
if(input[lpc+1] == '"') {
/* skip over the next char */
lpc++;
break;
}
/*fall through*/
case '"':
return lpc;
default:
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
crm_data_t*
parse_xml(const char *input, int *offset)
{
int len = 0, lpc = 0;
char ch = 0;
char *tag_name = NULL;
char *attr_name = NULL;
char *attr_value = NULL;
gboolean more = TRUE;
const char *error = NULL;
const char *our_input = input;
crm_data_t *new_obj = NULL;
if(input == NULL) {
return NULL;
}
if(offset != NULL) {
our_input = input + (*offset);
}
len = strlen(our_input);
while(lpc < len) {
if(our_input[lpc] != '<') {
} else if(our_input[lpc+1] == '!') {
crm_warn("XML Comments are not supported");
crm_debug_5("Skipping char %c", our_input[lpc]);
lpc++;
} else if(our_input[lpc+1] == '?') {
crm_debug_5("Skipping char %c", our_input[lpc]);
lpc++;
} else {
lpc++;
our_input += lpc;
break;
}
crm_debug_5("Skipping char %c", our_input[lpc]);
lpc++;
}
len = get_tag_name(our_input);
if(len < 0) {
return NULL;
}
crm_malloc0(tag_name, len+1);
strncpy(tag_name, our_input, len+1);
tag_name[len] = EOS;
crm_debug_4("Processing tag %s", tag_name);
new_obj = ha_msg_new(1);
CRM_DEV_ASSERT(crm_is_allocated(new_obj) == 1);
ha_msg_add(new_obj, F_XML_TAGNAME, tag_name);
lpc = len;
for(; more && error == NULL && lpc < (ssize_t)strlen(input); lpc++) {
ch = our_input[lpc];
crm_debug_5("Processing char %c[%d]", ch, lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '/':
if(our_input[lpc+1] == '>') {
more = FALSE;
}
break;
case '<':
if(our_input[lpc+1] != '/') {
crm_data_t *child = NULL;
crm_debug_4("Start parsing child...");
child = parse_xml(our_input, &lpc);
if(child == NULL) {
error = "error parsing child";
} else {
CRM_DEV_ASSERT(crm_is_allocated(child) == 1);
ha_msg_addstruct(
new_obj, crm_element_name(child), child);
crm_debug_4("Finished parsing child: %s",
crm_element_name(child));
ha_msg_del(child);
/* lpc++; /\* > *\/ */
}
} else {
lpc += 2; /* </ */
len = get_tag_name(our_input+lpc);
if(len < 0) {
error = "couldnt find tag";
} else if(strncmp(our_input+lpc, tag_name, len) == 0) {
more = FALSE;
lpc += len;
/* lpc++; /\* > *\/ */
if(our_input[lpc] != '>') {
error = "clase tag cannot contain attrs";
}
crm_debug_4("Finished parsing ourselves: %s",
crm_element_name(new_obj));
} else {
error = "Mismatching close tag";
crm_err("Expected: %s", tag_name);
}
}
break;
case '=':
lpc++; /* = */
/*fall through*/
case '"':
lpc++; /* " */
len = get_attr_value(our_input+lpc);
if(len < 0) {
error = "couldnt find attr_value";
} else {
crm_malloc0(attr_value, len+1);
strncpy(attr_value, our_input+lpc, len+1);
attr_value[len] = EOS;
lpc += len;
/* lpc++; /\* " *\/ */
crm_debug_4("creating nvpair: <%s %s=\"%s\"...",
tag_name,
crm_str(attr_name),
crm_str(attr_value));
ha_msg_add(new_obj, attr_name, attr_value);
crm_free(attr_name);
crm_free(attr_value);
}
break;
case '>':
case ' ':
case '\t':
case '\n':
break;
default:
len = get_attr_name(our_input+lpc);
if(len < 0) {
error = "couldnt find attr_name";
} else {
crm_malloc0(attr_name, len+1);
strncpy(attr_name, our_input+lpc, len+1);
attr_name[len] = EOS;
lpc += len;
crm_debug_4("found attr name: %s", attr_name);
lpc--; /* make sure the '=' is seen next time around */
}
break;
}
}
if(error) {
crm_err("Error parsing token: %s", error);
crm_err("Error at or before: %s", our_input+lpc-3);
return NULL;
}
crm_debug_4("Finished processing %s tag", tag_name);
crm_free(tag_name);
if(offset != NULL) {
(*offset) += lpc;
}
CRM_DEV_ASSERT(crm_is_allocated(new_obj) == 1);
return new_obj;
}
void
-log_xml_diff(int log_level, crm_data_t *diff, const char *function)
+log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function)
{
crm_data_t *added = find_xml_node(diff, "diff-added", FALSE);
crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE);
gboolean is_first = TRUE;
xml_child_iter(
removed, child, NULL,
log_data_element(function, "-", log_level, 0, child, TRUE);
if(is_first) {
is_first = FALSE;
} else {
crm_log_maybe(log_level, " --- ");
}
);
/* crm_log_maybe(log_level, " === "); */
is_first = TRUE;
xml_child_iter(
added, child, NULL,
log_data_element(function, "+", log_level, 0, child, TRUE);
if(is_first) {
is_first = FALSE;
} else {
crm_log_maybe(log_level, " --- ");
}
);
}
gboolean
apply_xml_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new)
{
gboolean result = TRUE;
crm_data_t *added = find_xml_node(diff, "diff-added", FALSE);
crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE);
crm_data_t *intermediate = NULL;
crm_data_t *diff_of_diff = NULL;
int root_nodes_seen = 0;
CRM_DEV_ASSERT(new != NULL);
if(crm_assert_failed) { return FALSE; }
crm_debug_2("Substraction Phase");
xml_child_iter(removed, child_diff, NULL,
CRM_DEV_ASSERT(root_nodes_seen == 0);
if(root_nodes_seen == 0) {
*new = subtract_xml_object(old, child_diff, FALSE);
}
root_nodes_seen++;
);
if(root_nodes_seen == 0) {
*new = copy_xml(old);
} else if(root_nodes_seen > 1) {
crm_err("(-) Diffs cannot contain more than one change set..."
" saw %d", root_nodes_seen);
result = FALSE;
}
root_nodes_seen = 0;
crm_debug_2("Addition Phase");
if(result) {
xml_child_iter(added, child_diff, NULL,
CRM_DEV_ASSERT(root_nodes_seen == 0);
if(root_nodes_seen == 0) {
add_xml_object(NULL, *new, child_diff);
}
root_nodes_seen++;
);
}
if(root_nodes_seen > 1) {
crm_err("(+) Diffs cannot contain more than one change set..."
" saw %d", root_nodes_seen);
result = FALSE;
#if CRM_DEV_BUILD
} else if(result) {
crm_debug_2("Verification Phase");
intermediate = diff_xml_object(old, *new, FALSE);
diff_of_diff = diff_xml_object(intermediate, diff, TRUE);
if(diff_of_diff != NULL) {
crm_warn("Diff application failed!");
/* log_xml_diff(LOG_DEBUG, diff_of_diff, "diff:diff_of_diff"); */
log_xml_diff(LOG_DEBUG, intermediate, "diff:actual_diff");
result = FALSE;
}
crm_free(diff_of_diff);
crm_free(intermediate);
#endif
diff_of_diff = NULL;
intermediate = NULL;
}
if(result == FALSE) {
log_xml_diff(LOG_DEBUG, diff, "diff:input_diff");
log_data_element("diff:input", NULL, LOG_DEBUG_2, 0, old, TRUE);
/* CRM_DEV_ASSERT(diff_of_diff != NULL); */
result = FALSE;
}
return result;
}
crm_data_t *
diff_xml_object(crm_data_t *old, crm_data_t *new, gboolean suppress)
{
crm_data_t *diff = NULL;
crm_data_t *tmp1 = NULL;
crm_data_t *added = NULL;
crm_data_t *removed = NULL;
tmp1 = subtract_xml_object(old, new, suppress);
if(tmp1 != NULL) {
diff = create_xml_node(NULL, "diff");
if(can_prune_leaf(tmp1)) {
ha_msg_del(tmp1);
tmp1 = NULL;
} else {
removed = create_xml_node(diff, "diff-removed");
added = create_xml_node(diff, "diff-added");
add_node_copy(removed, tmp1);
}
free_xml(tmp1);
}
tmp1 = subtract_xml_object(new, old, suppress);
if(tmp1 != NULL) {
if(diff == NULL) {
diff = create_xml_node(NULL, "diff");
}
if(can_prune_leaf(tmp1)) {
ha_msg_del(tmp1);
tmp1 = NULL;
} else {
if(removed == NULL) {
removed = create_xml_node(diff, "diff-removed");
}
if(added == NULL) {
added = create_xml_node(diff, "diff-added");
}
add_node_copy(added, tmp1);
}
free_xml(tmp1);
}
return diff;
}
gboolean
can_prune_leaf(crm_data_t *xml_node)
{
gboolean can_prune = TRUE;
/* return FALSE; */
xml_prop_iter(xml_node, prop_name, prop_value,
if(safe_str_eq(prop_name, XML_ATTR_ID)) {
continue;
} else if(safe_str_eq(prop_name, XML_ATTR_TSTAMP)) {
continue;
}
can_prune = FALSE;
);
xml_child_iter(xml_node, child, NULL,
if(can_prune_leaf(child)) {
cl_msg_remove_value(xml_node, child);
__counter--;
} else {
can_prune = FALSE;
}
);
return can_prune;
}
void
diff_filter_context(int context, int upper_bound, int lower_bound,
crm_data_t *xml_node, crm_data_t *parent)
{
crm_data_t *us = NULL;
crm_data_t *new_parent = parent;
const char *name = crm_element_name(xml_node);
CRM_DEV_ASSERT(xml_node != NULL && name != NULL);
if(crm_assert_failed) { return; }
us = create_xml_node(parent, name);
xml_prop_iter(xml_node, prop_name, prop_value,
lower_bound = context;
crm_xml_add(us, prop_name, prop_value);
);
if(lower_bound >= 0 || upper_bound >= 0) {
crm_xml_add(us, XML_ATTR_ID, ID(xml_node));
new_parent = us;
} else {
upper_bound = in_upper_context(0, context, xml_node);
if(upper_bound >= 0) {
crm_xml_add(us, XML_ATTR_ID, ID(xml_node));
new_parent = us;
} else {
free_xml(us);
us = NULL;
}
}
xml_child_iter(us, child, NULL,
diff_filter_context(
context, upper_bound-1, lower_bound-1,
child, new_parent);
);
}
int
in_upper_context(int depth, int context, crm_data_t *xml_node)
{
gboolean has_attributes = FALSE;
if(context == 0) {
return 0;
}
xml_prop_iter(xml_node, prop_name, prop_value,
has_attributes = TRUE;
break;
);
if(has_attributes) {
return depth;
} else if(depth < context) {
xml_child_iter(xml_node, child, NULL,
if(in_upper_context(depth+1, context, child)) {
return depth;
}
);
}
return 0;
}
crm_data_t *
subtract_xml_object(crm_data_t *left, crm_data_t *right, gboolean suppress)
{
gboolean skip = FALSE;
gboolean differences = FALSE;
crm_data_t *diff = NULL;
crm_data_t *child_diff = NULL;
crm_data_t *right_child = NULL;
const char *right_val = NULL;
const char *name = NULL;
int lpc = 0;
const char *filter[] = {
XML_ATTR_TSTAMP,
"last_written",
"debug_source",
"origin"
};
if(left == NULL) {
return NULL;
} else if(right == NULL) {
crm_debug_2("Processing <%s id=%s> (complete copy)",
crm_element_name(left), ID(left));
return copy_xml(left);
}
name = crm_element_name(left);
/* sanity check */
CRM_DEV_ASSERT(name != NULL);
if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(safe_str_eq(crm_element_name(left),
crm_element_name(right)));
if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(safe_str_eq(ID(left), ID(right)));
if(crm_assert_failed) { return NULL; }
diff = create_xml_node(NULL, name);
/* changes to name/value pairs */
crm_debug_2("Processing <%s id=%s>", crm_str(name), ID(left));
xml_prop_iter(left, prop_name, left_value,
skip = FALSE;
if(safe_str_eq(prop_name, XML_ATTR_ID)) {
skip = TRUE;
}
for(lpc = 0;
skip == FALSE && suppress && lpc < DIMOF(filter);
lpc++) {
if(safe_str_eq(prop_name, filter[lpc])) {
skip = TRUE;
}
}
if(skip) { continue; }
right_val = crm_element_value(right, prop_name);
if(right_val == NULL) {
differences = TRUE;
crm_xml_add(diff, prop_name, left_value);
crm_debug_3("\t%s: %s", crm_str(prop_name),
crm_str(left_value));
} else if(safe_str_eq(left_value, right_val)) {
crm_debug_2("\t%s: %s (removed)",
crm_str(prop_name),
crm_str(left_value));
} else {
differences = TRUE;
crm_xml_add(diff, prop_name, left_value);
crm_debug_2("\t%s: %s->%s",
crm_str(prop_name),
crm_str(left_value),
right_val);
}
);
/* changes to child objects */
xml_child_iter(
left, left_child, NULL,
right_child = find_entity(
right, crm_element_name(left_child), ID(left_child));
child_diff = subtract_xml_object(
left_child, right_child, suppress);
if(child_diff != NULL) {
differences = TRUE;
add_node_copy(diff, child_diff);
free_xml(child_diff);
}
);
if(differences == FALSE) {
free_xml(diff);
crm_debug_2("\tNo changes");
return NULL;
}
crm_xml_add(diff, XML_ATTR_ID, ID(left));
return diff;
}
int
add_xml_object(crm_data_t *parent, crm_data_t *target, const crm_data_t *update)
{
const char *object_id = NULL;
const char *object_name = NULL;
const char *right_val = NULL;
int result = 0;
CRM_DEV_ASSERT(update != NULL);
if(crm_assert_failed) { return 0; }
object_name = crm_element_name(update);
object_id = ID(update);
CRM_DEV_ASSERT(object_name != NULL);
if(crm_assert_failed) { return 0; }
if(target == NULL && object_id == NULL) {
/* placeholder object */
target = find_xml_node(parent, object_name, FALSE);
} else if(target == NULL) {
target = find_entity(parent, object_name, object_id);
}
if(target == NULL) {
target = add_node_copy(parent, update);
crm_debug_2("Added <%s id=%s>",
crm_str(object_name), crm_str(object_id));
CRM_DEV_ASSERT(target != NULL);
return 0;
}
crm_debug_2("Found node <%s id=%s> to update",
crm_str(object_name), crm_str(object_id));
xml_prop_iter(update, prop_name, left_value,
right_val = crm_element_value(target, prop_name);
if(right_val == NULL) {
crm_xml_add(target, prop_name, left_value);
crm_debug_2("\t%s: %s (added)",
crm_str(prop_name),
crm_str(left_value));
} else if(safe_str_neq(left_value, right_val)) {
crm_xml_add(target, prop_name, left_value);
crm_debug_2("\t%s: %s->%s",
crm_str(prop_name),
crm_str(left_value),
right_val);
}
);
CRM_DEV_ASSERT(cl_is_allocated(object_name));
if(object_id != NULL) {
CRM_DEV_ASSERT(cl_is_allocated(object_id));
}
crm_debug_3("Processing children of <%s id=%s>",
crm_str(object_name), crm_str(object_id));
xml_child_iter(
update, a_child, NULL,
int tmp_result = 0;
crm_debug_3("Updating child <%s id=%s>",
crm_element_name(a_child), ID(a_child));
tmp_result = add_xml_object(target, NULL, a_child);
if(tmp_result < 0) {
crm_err("Error updating child <%s id=%s>",
crm_element_name(a_child), ID(a_child));
/* only the first error is likely to be interesting */
if(result >= 0) {
result = tmp_result;
}
}
);
crm_debug_3("Finished with <%s id=%s>",
crm_str(object_name), crm_str(object_id));
return result;
}
gboolean
delete_xml_child(crm_data_t *parent, crm_data_t *child, crm_data_t *to_delete)
{
gboolean can_delete = FALSE;
const char *right_val = NULL;
CRM_DEV_ASSERT(child != NULL);
if(crm_assert_failed) { return FALSE; }
CRM_DEV_ASSERT(to_delete != NULL);
if(crm_assert_failed) { return FALSE; }
if(safe_str_eq(crm_element_name(to_delete), crm_element_name(child))) {
can_delete = TRUE;
}
xml_prop_iter(to_delete, prop_name, left_value,
if(can_delete == FALSE) {
break;
}
right_val = crm_element_value(child, prop_name);
if(safe_str_neq(left_value, right_val)) {
can_delete = FALSE;
}
);
if(can_delete && parent != NULL) {
crm_log_xml_debug(child, "Delete match found...");
cl_msg_remove_value(parent, child);
child = NULL;
} else if(can_delete) {
crm_log_xml_debug(child, "Cannot delete the search root");
}
xml_child_iter(
child, child_of_child, NULL,
/* only delete the first one */
if(can_delete) {
break;
}
can_delete = delete_xml_child(child, child_of_child, to_delete);
);
return can_delete;
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Apr 21, 7:39 PM (10 h, 19 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1663188
Default Alt Text
(242 KB)

Event Timeline