Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/crm/cib/callbacks.c b/crm/cib/callbacks.c
index e4aca646e9..3b333cdc0c 100644
--- a/crm/cib/callbacks.c
+++ b/crm/cib/callbacks.c
@@ -1,1437 +1,1436 @@
-/* $Id: callbacks.c,v 1.78 2005/09/02 12:34:16 andrew Exp $ */
+/* $Id: callbacks.c,v 1.79 2005/09/12 11:00:19 andrew 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 <cibprimatives.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_DEFAULT, 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);
crm_info("Setting %s callbacks for %s: %s",
type, cib_client->name, on_off?"on":"off");
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);
if(safe_str_eq(cib_client->name, CRM_SYSTEM_TENGINE)) {
/* The TE is _always_ interested in these
* Enable now to avoid timing issues
*/
cib_client->diffs = TRUE;
}
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) {
if(cib_server_ops[call_type].modifies_cib
&& !(call_options & cib_inhibit_bcast)) {
/* we need to send an update anyway */
needs_reply = TRUE;
} else {
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("Ignoring msg for master instance");
return;
} else if(host != NULL) {
/* this is for a specific instance and we're not it */
crm_debug("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("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, FALSE);
} else {
crm_debug("Forwarding %s op to master instance", op);
send_ha_message(hb_conn, forward_msg, NULL, FALSE);
}
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_2("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_2("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_2("Performing notification");
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_2("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);
int diff_add_updates = 0;
int diff_add_epoch = 0;
int diff_add_admin_epoch = 0;
int diff_del_updates = 0;
int diff_del_epoch = 0;
int diff_del_admin_epoch = 0;
cib_diff_version_details(
result_diff,
&diff_add_admin_epoch, &diff_add_epoch, &diff_add_updates,
&diff_del_admin_epoch, &diff_del_epoch, &diff_del_updates);
crm_debug("Sending update diff %d.%d.%d -> %d.%d.%d",
diff_del_admin_epoch,diff_del_epoch,diff_del_updates,
diff_add_admin_epoch,diff_add_epoch,diff_add_updates);
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, TRUE);
crm_msg_del(op_bcast);
} else if((call_options & cib_discard_reply) == 0) {
crm_debug_2("Sending replies");
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, FALSE);
}
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 {
- do_id_check(input_fragment);
+ do_id_check(input_fragment, NULL);
}
} 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);
- do_id_check(input);
+ do_id_check(input, NULL);
}
}
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);
const char *seq = cl_get_string(msg, F_SEQ);
const char *op = cl_get_string(msg, F_CIB_OPERATION);
crm_log_message_adv(LOG_MSG, "Peer[inbound]", msg);
crm_debug_2("Operation %s from peer %s", op, originator);
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_2("Discarding message %s/%s:"
" membership not established",
originator, seq);
return;
} else if(g_hash_table_lookup(ccm_membership, originator) == NULL) {
crm_debug_2("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", seq);
return;
}
crm_debug("Processing msg %s (%s) from peer %s", seq, op, originator);
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) {
unsigned int members = 0;
int offset = 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/cibprimatives.h b/crm/cib/cibprimatives.h
index 3aa2d5d6a2..b173081dcd 100644
--- a/crm/cib/cibprimatives.h
+++ b/crm/cib/cibprimatives.h
@@ -1,81 +1,79 @@
-/* $Id: cibprimatives.h,v 1.12 2005/07/11 12:13:07 andrew Exp $ */
+/* $Id: cibprimatives.h,v 1.13 2005/09/12 11:00:19 andrew 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 CIB_PRIMATIVES__H
#define CIB_PRIMATIVES__H
#include <portability.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <clplumbing/ipc.h>
#include <clplumbing/cl_log.h>
#include <crm/common/xml.h>
#define IS_DAEMON
#define IPC_COMMS
typedef crm_data_t cibStatus;
typedef crm_data_t cibResource;
typedef crm_data_t cibConstraint;
typedef crm_data_t cibHaNode;
/* extern gboolean initialized; */
/* extern crm_data_t *the_cib; */
/* extern crm_data_t *node_search; */
/* extern crm_data_t *resource_search; */
/* extern crm_data_t *constraint_search; */
/* extern crm_data_t *status_search; */
/* extern const char* crm_system_name; */
extern crm_data_t *get_the_CIB(void);
extern int addResource (crm_data_t *cib, crm_data_t *anXmlNode);
extern int addConstraint(crm_data_t *cib, crm_data_t *anXmlNode);
extern int addHaNode (crm_data_t *cib, crm_data_t *anXmlNode);
extern int addStatus (crm_data_t *cib, crm_data_t *anXmlNode);
extern crm_data_t *findResource (crm_data_t *cib, const char *id);
extern crm_data_t *findConstraint(crm_data_t *cib, const char *id);
extern crm_data_t *findHaNode (crm_data_t *cib, const char *id);
extern crm_data_t *findStatus (crm_data_t *cib, const char *id);
extern int updateResource (crm_data_t *cib, crm_data_t *anXmlNode);
extern int updateConstraint(crm_data_t *cib, crm_data_t *anXmlNode);
extern int updateHaNode (crm_data_t *cib, crm_data_t *anXmlNode);
extern int updateStatus (crm_data_t *cib, crm_data_t *anXmlNode);
extern int delResource (crm_data_t *cib, crm_data_t *delete_spec);
extern int delConstraint(crm_data_t *cib, crm_data_t *delete_spec);
extern int delHaNode (crm_data_t *cib, crm_data_t *delete_spec);
extern int delStatus (crm_data_t *cib, crm_data_t *delete_spec);
extern int add_cib_object (crm_data_t *parent, crm_data_t *new_obj);
extern int delete_cib_object(crm_data_t *parent, crm_data_t *delete_spec);
extern int update_cib_object(crm_data_t *parent, crm_data_t *new_obj);
-void do_id_check(crm_data_t *xml_obj);
-
#endif
diff --git a/crm/cib/io.c b/crm/cib/io.c
index 88ed4adf18..d61d5c1697 100644
--- a/crm/cib/io.c
+++ b/crm/cib/io.c
@@ -1,528 +1,528 @@
-/* $Id: io.c,v 1.30 2005/09/02 12:31:07 andrew Exp $ */
+/* $Id: io.c,v 1.31 2005/09/12 11:00:19 andrew 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 <sys/stat.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <heartbeat.h>
#include <crm/crm.h>
#include <cibio.h>
#include <crm/cib.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <clplumbing/cl_misc.h>
#include <cibprimatives.h>
#include <crm/dmalloc_wrapper.h>
const char * local_resource_path[] =
{
XML_CIB_TAG_STATUS,
};
const char * resource_path[] =
{
XML_CIB_TAG_RESOURCES,
};
const char * node_path[] =
{
XML_CIB_TAG_NODES,
};
const char * constraint_path[] =
{
XML_CIB_TAG_CONSTRAINTS,
};
gboolean initialized = FALSE;
crm_data_t *the_cib = NULL;
crm_data_t *node_search = NULL;
crm_data_t *resource_search = NULL;
crm_data_t *constraint_search = NULL;
crm_data_t *status_search = NULL;
gboolean cib_writes_enabled = TRUE;
extern char *ccm_transition_id;
extern gboolean cib_have_quorum;
extern GHashTable *peer_hash;
int set_connected_peers(crm_data_t *xml_obj);
void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data);
/*
* It is the callers responsibility to free the output of this function
*/
crm_data_t*
readCibXml(char *buffer)
{
crm_data_t *root = NULL;
if(buffer != NULL) {
root = string2xml(buffer);
}
- do_id_check(root);
+ do_id_check(root, NULL);
if (verifyCibXml(root) == FALSE) {
free_xml(root);
root = createEmptyCib();
crm_xml_add(root, XML_ATTR_GENERATION_ADMIN, "0");
crm_xml_add(root, XML_ATTR_GENERATION, "0");
crm_xml_add(root, XML_ATTR_NUMUPDATES, "0");
}
return root;
}
/*
* It is the callers responsibility to free the output of this function
*/
crm_data_t*
readCibXmlFile(const char *filename)
{
int s_res = -1;
struct stat buf;
crm_data_t *root = NULL;
if(filename != NULL) {
s_res = stat(filename, &buf);
}
if (s_res == 0) {
FILE *cib_file = fopen(filename, "r");
root = file2xml(cib_file);
crm_xml_add(root, "generated", XML_BOOLEAN_FALSE);
fclose(cib_file);
} else {
crm_warn("Stat of (%s) failed, file does not exist.",
CIB_FILENAME);
}
if(root != NULL) {
int lpc = 0;
const char *value = NULL;
const char *name = NULL;
crm_data_t *status = get_object_root(XML_CIB_TAG_STATUS, root);
for (; status != NULL && lpc < status->nfields; ) {
if(status->types[lpc] != FT_STRUCT) {
lpc++;
continue;
}
CRM_DEV_ASSERT(cl_msg_remove_offset(status, lpc) == HA_OK);
/* dont get stuck in an infinite loop */
if(crm_assert_failed) {
lpc++;
}
}
name = XML_ATTR_GENERATION_ADMIN;
value = crm_element_value(root, name);
if(value == NULL) {
crm_xml_add(root, name, "0");
}
name = XML_ATTR_GENERATION;
value = crm_element_value(root, name);
if(value == NULL) {
crm_xml_add(root, name, "0");
}
name = XML_ATTR_NUMUPDATES;
value = crm_element_value(root, name);
if(value == NULL) {
crm_xml_add(root, name, "0");
}
- do_id_check(root);
+ do_id_check(root, NULL);
}
if (verifyCibXml(root) == FALSE) {
free_xml(root);
root = NULL;
}
return root;
}
/*
* The caller should never free the return value
*/
crm_data_t*
get_the_CIB(void)
{
return the_cib;
}
gboolean
uninitializeCib(void)
{
crm_data_t *tmp_cib = the_cib;
if(tmp_cib == NULL) {
crm_err("The CIB has already been deallocated.");
return FALSE;
}
initialized = FALSE;
the_cib = NULL;
node_search = NULL;
resource_search = NULL;
constraint_search = NULL;
status_search = NULL;
crm_err("Deallocating the CIB.");
free_xml(tmp_cib);
crm_err("The CIB has been deallocated.");
return TRUE;
}
/*
* This method will not free the old CIB pointer or the new one.
* We rely on the caller to have saved a pointer to the old CIB
* and to free the old/bad one depending on what is appropriate.
*/
gboolean
initializeCib(crm_data_t *new_cib)
{
#if 0
if(new_cib != NULL) {
crm_set_element_parent(new_cib, NULL);
}
#endif
if (verifyCibXml(new_cib)) {
initialized = FALSE;
the_cib = new_cib;
/* update search paths */
/* not used yet...
node_search =
get_object_root(XML_CIB_TAG_NODES, new_cib);
resource_search =
get_object_root(XML_CIB_TAG_RESOURCES, new_cib);
constraint_search =
get_object_root(XML_CIB_TAG_CONSTRAINTS, new_cib);
status_search =
get_object_root(XML_CIB_TAG_STATUS, new_cib);
*/
initialized = TRUE;
}
if(initialized == FALSE) {
crm_warn("CIB Verification failed");
the_cib = NULL;
} else {
const char *option = "suppress_cib_writes";
const char *value = NULL;
crm_data_t *config = get_object_root(
XML_CIB_TAG_CRMCONFIG, new_cib);
crm_data_t * a_default = find_entity(
config, XML_CIB_TAG_NVPAIR, option);
if(a_default != NULL) {
value = crm_element_value(
a_default, XML_NVPAIR_ATTR_VALUE);
}
if(value == NULL) {
crm_warn("Option %s not set", option);
if(cib_writes_enabled == FALSE) {
crm_debug("Disk writes to %s enabled",
CIB_FILENAME);
}
cib_writes_enabled = TRUE;
} else {
gboolean suppress = FALSE;
cl_str_to_boolean(value, &suppress);
if(cib_writes_enabled == suppress) {
cib_writes_enabled = !suppress;
if(cib_writes_enabled) {
crm_debug("Disk writes to %s enabled",
CIB_FILENAME);
} else {
crm_notice("Disabling CIB disk writes");
}
}
}
crm_debug_2("Disk writes to %s %s", CIB_FILENAME,
cib_writes_enabled?"enabled":"DISABLED");
set_connected_peers(the_cib);
set_transition(the_cib);
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);
}
}
return initialized;
}
int
moveFile(const char *oldname,
const char *newname,
gboolean backup,
char *ext)
{
/* move 'oldname' to 'newname' by creating a hard link to it
* and then removing the original hard link
*/
int res = 0;
struct stat tmp;
int s_res = stat(newname, &tmp);
if (s_res >= 0)
{
if (backup == TRUE) {
char backname[1024];
static const char *back_ext = "bak";
if (ext != NULL) { back_ext = (char*)ext; }
snprintf(backname, sizeof(backname)-1,
"%s.%s", newname, back_ext);
moveFile(newname, backname, FALSE, NULL);
} else {
res = unlink(newname);
if (res < 0) {
perror("Could not remove the current backup of Cib");
return -1;
}
}
}
s_res = stat(oldname, &tmp);
if (s_res >= 0) {
res = link(oldname, newname);
if (res < 0) {
perror("Could not create backup of current Cib");
return -2;
}
res = unlink(oldname);
if (res < 0) {
perror("Could not unlink the current Cib");
return -3;
}
}
return 0;
}
int
activateCibBuffer(char *buffer, const char *filename)
{
int result = -1;
crm_data_t *local_cib = NULL;
local_cib = readCibXml(buffer);
result = activateCibXml(local_cib, filename);
return result;
}
/*
* This method will free the old CIB pointer on success and the new one
* on failure.
*/
#define ACTIVATION_DIFFS 0
int
activateCibXml(crm_data_t *new_cib, const char *filename)
{
int error_code = cib_ok;
crm_data_t *diff = NULL;
crm_data_t *saved_cib = get_the_CIB();
const char *filename_bak = CIB_BACKUP; /* calculate */
crm_log_xml_debug_4(new_cib, "Attempting to activate CIB");
CRM_ASSERT(new_cib != saved_cib);
crm_validate_data(new_cib);
if(saved_cib != NULL) {
crm_validate_data(saved_cib);
}
if (initializeCib(new_cib) == FALSE) {
crm_warn("Ignoring invalid or NULL Cib");
error_code = -5;
} else if(cib_writes_enabled) {
if(saved_cib != NULL) {
CRM_DEV_ASSERT(0 >= moveFile(filename,
filename_bak,
FALSE, NULL));
if (crm_assert_failed) {
crm_warn("Could not make backup of the current"
" Cib... aborting update.");
error_code = -1;
}
}
if(error_code == cib_ok) {
crm_debug_3("Writing CIB out to %s", CIB_FILENAME);
CRM_DEV_ASSERT(new_cib != NULL);
CRM_DEV_ASSERT(write_xml_file(
new_cib, CIB_FILENAME) >= 0);
if (crm_assert_failed) {
error_code = -4;
}
}
if(error_code == -4 && saved_cib != NULL) {
CRM_DEV_ASSERT(moveFile(filename_bak,
filename, FALSE, NULL) >= 0);
if (crm_assert_failed){
crm_crit("Could not restore the backup of the "
" current Cib... panic!");
error_code = -2;
/* should probably exit here */
}
}
CRM_DEV_ASSERT(saved_cib != NULL || error_code == cib_ok);
if(crm_assert_failed) {
/* oh we are so dead */
crm_crit("Could not write out new CIB and no saved"
" version to revert to");
error_code = -3;
} else if(error_code != cib_ok) {
crm_crit("Update of Cib failed (%d)... reverting"
" to last known valid version",
error_code);
CRM_DEV_ASSERT(initializeCib(saved_cib));
if (crm_assert_failed) {
/* oh we are so dead */
crm_crit("Could not re-initialize with the old"
" CIB. Can anyone say corruption?");
error_code = -3;
}
}
}
#if ACTIVATION_DIFFS
/* Make sure memory is cleaned up appropriately */
if(saved_cib != NULL && new_cib != NULL) {
diff = diff_cib_object(saved_cib, new_cib, -1);
}
if (error_code != cib_ok) {
crm_err("Changes could not be activated: %s",
cib_error2string(error_code));
log_cib_diff(LOG_WARNING, diff, __FUNCTION__);
free_xml(new_cib);
} else if(saved_cib != NULL) {
crm_debug_2("Changes activated");
log_cib_diff(LOG_DEBUG, diff, __FUNCTION__);
crm_validate_data(saved_cib);
free_xml(saved_cib);
}
free_xml(diff);
#else
if (error_code != cib_ok) {
crm_err("Changes could not be activated: %s",
cib_error2string(error_code));
free_xml(new_cib);
} else if(saved_cib != NULL) {
crm_debug_2("Changes activated");
crm_validate_data(saved_cib);
free_xml(saved_cib);
}
#endif
diff = NULL;
return error_code;
}
void
set_transition(crm_data_t *xml_obj)
{
const char *current = crm_element_value(
xml_obj, XML_ATTR_CCM_TRANSITION);
if(safe_str_neq(current, ccm_transition_id)) {
crm_debug("Set transition to %s", ccm_transition_id);
crm_xml_add(the_cib, XML_ATTR_CCM_TRANSITION,ccm_transition_id);
}
}
int
set_connected_peers(crm_data_t *xml_obj)
{
int active = 0;
int current = 0;
char *peers_s = NULL;
const char *current_s = crm_element_value(
xml_obj, XML_ATTR_NUMPEERS);
g_hash_table_foreach(peer_hash, GHFunc_count_peers, &active);
current = crm_atoi(current_s, "0");
if(current != active) {
peers_s = crm_itoa(active);
crm_xml_add(xml_obj, XML_ATTR_NUMPEERS, peers_s);
crm_debug("Set peers to %s", peers_s);
crm_free(peers_s);
}
return active;
}
void GHFunc_count_peers(gpointer key, gpointer value, gpointer user_data)
{
int *active = user_data;
if(safe_str_eq(value, ONLINESTATUS)) {
(*active)++;
} else if(safe_str_eq(value, JOINSTATUS)) {
(*active)++;
}
}
diff --git a/crm/cib/primatives.c b/crm/cib/primatives.c
index d1bd233ad4..d2e953f1be 100644
--- a/crm/cib/primatives.c
+++ b/crm/cib/primatives.c
@@ -1,633 +1,566 @@
-/* $Id: primatives.c,v 1.26 2005/08/25 08:26:48 andrew Exp $ */
+/* $Id: primatives.c,v 1.27 2005/09/12 11:00:19 andrew 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 <clplumbing/cl_log.h>
#include <crm/crm.h>
#include <crm/cib.h>
#include <cibprimatives.h>
#include <notify.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/dmalloc_wrapper.h>
/*
* In case of confusion, this is the memory management policy for
* all functions in this file.
*
* All add/modify functions use copies of supplied data.
* It is therefore appropriate that the callers free the supplied data
* at some point after the function has finished.
*
* All delete functions will handle the freeing of deleted data
* but not the function arguments.
*/
void update_node_state(crm_data_t *existing_node, crm_data_t *update);
/* --- Resource */
int
addResource(crm_data_t *cib, crm_data_t *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Adding " XML_CIB_TAG_RESOURCE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_RESOURCES, cib);
return add_cib_object(root, anXmlNode);
}
crm_data_t*
findResource(crm_data_t *cib, const char *id)
{
crm_data_t *root = NULL, *ret = NULL;
root = get_object_root(XML_CIB_TAG_RESOURCES, cib);
ret = find_entity(root, XML_CIB_TAG_RESOURCE, id);
return ret;
}
int
updateResource(crm_data_t *cib, crm_data_t *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root = NULL;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Updating " XML_CIB_TAG_RESOURCE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_RESOURCES, cib);
return update_cib_object(root, anXmlNode);
}
int
delResource(crm_data_t *cib, crm_data_t *delete_spec)
{
const char *id = ID(delete_spec);
crm_data_t *root;
if(id == NULL || strlen(id) == 0) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Deleting " XML_CIB_TAG_RESOURCE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_RESOURCES, cib);
return delete_cib_object(root, delete_spec);
}
/* --- Constraint */
int
addConstraint(crm_data_t *cib, crm_data_t *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Adding " XML_CIB_TAG_CONSTRAINT " (%s)...", id);
root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
return add_cib_object(root, anXmlNode);
}
crm_data_t*
findConstraint(crm_data_t *cib, const char *id)
{
crm_data_t *root = NULL, *ret = NULL;
root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
ret = find_entity(root, XML_CIB_TAG_CONSTRAINT, id);
return ret;
}
int
updateConstraint(crm_data_t *cib, crm_data_t *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Updating " XML_CIB_TAG_CONSTRAINT " (%s)...", id);
root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
return update_cib_object(root, anXmlNode);
}
int
delConstraint(crm_data_t *cib, crm_data_t *delete_spec)
{
const char *id = ID(delete_spec);
crm_data_t *root;
if(id == NULL || strlen(id) == 0) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Deleting " XML_CIB_TAG_CONSTRAINT " (%s)...", id);
root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
return delete_cib_object(root, delete_spec);
}
/* --- HaNode */
int
addHaNode(crm_data_t *cib, crm_data_t *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Adding " XML_CIB_TAG_NODE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_NODES, cib);
return add_cib_object(root, anXmlNode);
}
crm_data_t*
findHaNode(crm_data_t *cib, const char *id)
{
crm_data_t *root = NULL, *ret = NULL;
root = get_object_root(XML_CIB_TAG_NODES, cib);
ret = find_entity(root, XML_CIB_TAG_NODE, id);
return ret;
}
int
updateHaNode(crm_data_t *cib, cibHaNode *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Updating " XML_CIB_TAG_NODE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_NODES, cib);
return update_cib_object(root, anXmlNode);
}
int
delHaNode(crm_data_t *cib, crm_data_t *delete_spec)
{
const char *id = ID(delete_spec);
crm_data_t *root;
if(id == NULL || strlen(id) == 0) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Deleting " XML_CIB_TAG_NODE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_CONSTRAINTS, cib);
return delete_cib_object(root, delete_spec);
}
/* --- Status */
int
addStatus(crm_data_t *cib, crm_data_t *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Adding " XML_CIB_TAG_NODE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_STATUS, cib);
return add_cib_object(root, anXmlNode);
}
crm_data_t*
findStatus(crm_data_t *cib, const char *id)
{
crm_data_t *root = NULL, *ret = NULL;
root = get_object_root(XML_CIB_TAG_STATUS, cib);
ret = find_entity(root, XML_CIB_TAG_STATE, id);
return ret;
}
int
updateStatus(crm_data_t *cib, crm_data_t *anXmlNode)
{
const char *id = ID(anXmlNode);
crm_data_t *root;
if (id == NULL || strlen(id) < 1) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Updating " XML_CIB_TAG_NODE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_STATUS, cib);
return update_cib_object(root, anXmlNode);
}
int
delStatus(crm_data_t *cib, crm_data_t *delete_spec)
{
const char *id = ID(delete_spec);
crm_data_t *root;
if(id == NULL || strlen(id) == 0) {
return CIBRES_MISSING_ID;
}
crm_debug_2("Deleting " XML_CIB_TAG_STATE " (%s)...", id);
root = get_object_root(XML_CIB_TAG_STATUS, cib);
return delete_cib_object(root, delete_spec);
}
int
delete_cib_object(crm_data_t *parent, crm_data_t *delete_spec)
{
const char *object_name = NULL;
const char *object_id = NULL;
crm_data_t *equiv_node = NULL;
int result = cib_ok;
if(delete_spec != NULL) {
object_name = crm_element_name(delete_spec);
}
object_id = crm_element_value(delete_spec, XML_ATTR_ID);
crm_debug_2("Processing: <%s id=%s>",
crm_str(object_name), crm_str(object_id));
if(delete_spec == NULL) {
result = cib_NOOBJECT;
} else if(parent == NULL) {
result = cib_NOPARENT;
} else if(object_id == NULL) {
/* placeholder object */
equiv_node = find_xml_node(parent, object_name, FALSE);
} else {
equiv_node = find_entity(parent, object_name, object_id);
}
if(result != cib_ok) {
; /* nothing */
} else if(equiv_node == NULL) {
result = cib_NOTEXISTS;
} else if(xml_has_children(delete_spec) == FALSE) {
/* only leaves are deleted */
crm_debug("Removing leaf: <%s id=%s>",
crm_str(object_name), crm_str(object_id));
zap_xml_from_parent(parent, equiv_node);
} else {
xml_child_iter(
delete_spec, child, NULL,
int tmp_result = delete_cib_object(equiv_node, child);
/* only the first error is likely to be interesting */
if(result == cib_ok) {
result = tmp_result;
}
);
}
return result;
}
int
add_cib_object(crm_data_t *parent, crm_data_t *new_obj)
{
enum cib_errors result = cib_ok;
const char *object_name = NULL;
const char *object_id = NULL;
crm_data_t *equiv_node = NULL;
if(new_obj != NULL) {
object_name = crm_element_name(new_obj);
}
object_id = crm_element_value(new_obj, XML_ATTR_ID);
if(new_obj == NULL) {
result = cib_NOOBJECT;
} else if(parent == NULL) {
result = cib_NOPARENT;
} else if(object_id == NULL) {
/* placeholder object */
equiv_node = find_xml_node(parent, object_name, FALSE);
} else {
equiv_node = find_entity(parent, object_name, object_id);
}
if(result != cib_ok) {
; /* do nothing */
} else if(equiv_node != NULL) {
result = cib_EXISTS;
} else if(add_node_copy(parent, new_obj) == NULL) {
result = cib_NODECOPY;
}
return result;
}
int
update_cib_object(crm_data_t *parent, crm_data_t *update)
{
const char *replace = NULL;
const char *object_name = NULL;
const char *object_id = NULL;
crm_data_t *target = NULL;
int result = cib_ok;
CRM_DEV_ASSERT(update != NULL);
if(crm_assert_failed) { return cib_NOOBJECT; }
CRM_DEV_ASSERT(parent != NULL);
if(crm_assert_failed) { return cib_NOPARENT; }
object_name = crm_element_name(update);
object_id = ID(update);
CRM_DEV_ASSERT(object_name != NULL);
if(crm_assert_failed) { return cib_NOOBJECT; }
if(object_id == NULL) {
/* placeholder object */
target = find_xml_node(parent, object_name, FALSE);
} else {
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);
if(crm_assert_failed) { return cib_NODECOPY; }
return cib_ok;
}
crm_debug_2("Found node <%s id=%s> to update",
crm_str(object_name), crm_str(object_id));
replace = crm_element_value(update, XML_CIB_ATTR_REPLACE);
if(replace != NULL) {
crm_data_t *remove = find_xml_node(target, replace, FALSE);
if(remove != NULL) {
crm_debug_3("Replacing node <%s> in <%s>",
replace, crm_element_name(target));
zap_xml_from_parent(target, remove);
}
xml_remove_prop(update, XML_CIB_ATTR_REPLACE);
xml_remove_prop(target, XML_CIB_ATTR_REPLACE);
}
if(safe_str_eq(XML_CIB_TAG_STATE, object_name)){
update_node_state(target, update);
} else {
copy_in_properties(target, update);
}
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 = update_cib_object(target, a_child);
/* only the first error is likely to be interesting */
if(tmp_result != cib_ok) {
crm_err("Error updating child <%s id=%s>",
crm_element_name(a_child), ID(a_child));
if(result == cib_ok) {
result = tmp_result;
}
}
);
crm_debug_3("Finished with <%s id=%s>",
crm_str(object_name), crm_str(object_id));
return result;
}
void
update_node_state(crm_data_t *target, crm_data_t *update)
{
const char *source = NULL;
gboolean any_updates = FALSE;
gboolean clear_stonith = FALSE;
gboolean clear_shutdown = FALSE;
xml_prop_iter(
update, local_prop_name, local_prop_value,
if(local_prop_name == NULL) {
/* error */
} else if(strcmp(local_prop_name, XML_ATTR_ID) == 0) {
} else if(strcmp(local_prop_name, XML_ATTR_TSTAMP) == 0) {
} else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_SHUTDOWN) == 0) {
clear_shutdown = TRUE;
} else if(strcmp(local_prop_name, XML_CIB_ATTR_CLEAR_STONITH) == 0) {
clear_stonith = TRUE;
clear_shutdown = TRUE;
} else if(strcmp(local_prop_name, XML_CIB_ATTR_SOURCE) == 0) {
source = local_prop_value;
} else {
any_updates = TRUE;
crm_xml_add(target, local_prop_name, local_prop_value);
}
);
xml_remove_prop(target, XML_CIB_ATTR_CLEAR_SHUTDOWN);
if(clear_shutdown) {
/* unset XML_CIB_ATTR_SHUTDOWN */
if(crm_element_value(target, XML_CIB_ATTR_SHUTDOWN) != NULL) {
crm_debug_2("Clearing %s", XML_CIB_ATTR_SHUTDOWN);
xml_remove_prop(target, XML_CIB_ATTR_SHUTDOWN);
any_updates = TRUE;
}
}
xml_remove_prop(target, XML_CIB_ATTR_CLEAR_STONITH);
if(clear_stonith) {
/* unset XML_CIB_ATTR_STONITH */
if(crm_element_value(target, XML_CIB_ATTR_STONITH) != NULL) {
crm_debug_2("Clearing %s", XML_CIB_ATTR_STONITH);
xml_remove_prop(target, XML_CIB_ATTR_STONITH);
any_updates = TRUE;
}
}
if(any_updates) {
set_node_tstamp(target);
crm_xml_add(target, XML_CIB_ATTR_SOURCE, source);
}
}
-void
-do_id_check(crm_data_t *xml_obj)
-{
- int lpc = 0;
- cl_uuid_t new_uuid;
- char *new_uuid_s = NULL;
- const char *tag_name = NULL;
- const char *new_uuid_s2 = NULL;
-
- const char *allowed_list[] = {
- XML_TAG_CIB,
- XML_CIB_TAG_NODES,
- XML_CIB_TAG_RESOURCES,
- XML_CIB_TAG_CONSTRAINTS,
- XML_CIB_TAG_STATUS,
- XML_CIB_TAG_LRM,
- XML_LRM_TAG_RESOURCES,
- "operations",
- };
-
- if(xml_obj == NULL) {
- return;
- }
-
- xml_child_iter(
- xml_obj, xml_child, NULL,
- do_id_check(xml_child);
- );
-
- tag_name = TYPE(xml_obj);
-
- xml_prop_iter(
- xml_obj, local_prop_name, local_prop_value,
- if(safe_str_eq(local_prop_name, XML_ATTR_ID)) {
- continue;
-
- } else if(ID(xml_obj) != NULL) {
- return;
- }
-
- for(lpc = 0; lpc < DIMOF(allowed_list); lpc++) {
- if(safe_str_eq(tag_name, allowed_list[lpc])) {
- /* this tag is never meant to have an ID */
- return;
- }
- }
-
- /* create a UUID and assign it as the ID */
- crm_malloc0(new_uuid_s, sizeof(char)*38);
- cl_uuid_generate(&new_uuid);
- cl_uuid_unparse(&new_uuid, new_uuid_s);
-
- new_uuid_s2 = crm_xml_add(xml_obj, XML_ATTR_ID, new_uuid_s);
- crm_err("Object with attributes but no ID field detected."
- " Assigned: %s", ID(xml_obj));
- crm_log_xml_warn(xml_obj, "Updated object");
-
- CRM_DEV_ASSERT(cl_is_allocated(new_uuid_s));
- CRM_DEV_ASSERT(cl_is_allocated(new_uuid_s2));
-
- crm_free(new_uuid_s);
-
- CRM_DEV_ASSERT(cl_is_allocated(new_uuid_s2));
- return;
-
- );
-}
diff --git a/include/crm/common/util.h b/include/crm/common/util.h
index 14d96de828..f169b76554 100644
--- a/include/crm/common/util.h
+++ b/include/crm/common/util.h
@@ -1,110 +1,111 @@
-/* $Id: util.h,v 1.21 2005/08/08 12:05:02 andrew Exp $ */
+/* $Id: util.h,v 1.22 2005/09/12 11:00:19 andrew 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_UTIL__H
#define CRM_COMMON_UTIL__H
#include <signal.h>
#include <crm/common/xml.h>
#include <hb_api.h>
#include <ocf/oc_event.h>
#include <lrm/lrm_api.h>
#define DEBUG_INC SIGUSR1
#define DEBUG_DEC SIGUSR2
extern unsigned int crm_log_level;
extern gboolean crm_log_init(const char *entity);
extern void do_crm_log(int log_level, const char *file, const char *function,
const char *format, ...) G_GNUC_PRINTF(4,5);
/* returns the old value */
extern unsigned int set_crm_log_level(unsigned int level);
extern unsigned int get_crm_log_level(void);
extern char *crm_itoa(int an_int);
extern char *crm_strdup(const char *a);
extern char *generate_hash_key(const char *crm_msg_reference,
const char *sys);
extern char *generate_hash_value(const char *src_node,
const char *src_subsys);
extern gboolean decode_hash_value(gpointer value,
char **node,
char **subsys);
extern gboolean decodeNVpair(const char *srcstring,
char separator,
char **name,
char **value);
extern int compare_version(const char *version1, const char *version2);
extern char *generateReference(const char *custom1, const char *custom2);
extern void alter_debug(int nsig);
extern void g_hash_destroy_str(gpointer data);
extern void set_uuid(
ll_cluster_t* hb, crm_data_t *node, const char *attr, const char *uname);
extern void crm_set_ha_options(ll_cluster_t *hb_cluster);
extern gboolean crm_is_true(const char * s);
extern int crm_str_to_boolean(const char * s, int * ret);
extern long crm_get_msec(const char * input);
extern gboolean ccm_have_quorum(oc_ed_t event);
extern const char *ccm_event_name(oc_ed_t event);
extern const char *op_status2text(op_status_t status);
extern char *generate_op_key(
const char *rsc_id, const char *op_type, int interval);
extern char *generate_notify_key(
const char *rsc_id, const char *notify_type, const char *op_type);
extern gboolean crm_mem_stats(volatile cl_mem_stats_t *mem_stats);
extern void crm_zero_mem_stats(volatile cl_mem_stats_t *stats);
extern char *generate_transition_magic(
const char *transition_key, int op_status);
extern gboolean decode_transition_magic(
const char *magic, char **uuid, int *transition_id, int *op_status);
extern char *generate_transition_key(int transition_id, const char *node);
extern gboolean decode_transition_key(
const char *key, char **uuid, int *transition_id);
+extern char *crm_concat(const char *prefix, const char *suffix, char join);
#endif
diff --git a/include/crm/common/xml.h b/include/crm/common/xml.h
index 1b2787c406..0bbec5f6f3 100644
--- a/include/crm/common/xml.h
+++ b/include/crm/common/xml.h
@@ -1,281 +1,282 @@
-/* $Id: xml.h,v 1.28 2005/08/09 07:58:10 andrew Exp $ */
+/* $Id: xml.h,v 1.29 2005/09/12 11:00:19 andrew 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);
extern GHashTable *xml2list(crm_data_t *parent);
+extern void do_id_check(crm_data_t *xml_obj, GHashTable *id_hash);
/*
* 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(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/utils.c b/lib/crm/common/utils.c
index a10523fe68..a08e0b04f8 100644
--- a/lib/crm/common/utils.c
+++ b/lib/crm/common/utils.c
@@ -1,1028 +1,1025 @@
-/* $Id: utils.c,v 1.23 2005/08/17 09:03:24 andrew Exp $ */
+/* $Id: utils.c,v 1.24 2005/09/12 11:00:19 andrew 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>
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <heartbeat.h>
#include <ha_msg.h>
#include <clplumbing/cl_log.h>
#include <clplumbing/cl_signal.h>
#include <clplumbing/cl_syslog.h>
#include <clplumbing/cl_misc.h>
#include <clplumbing/coredumps.h>
#include <time.h>
#include <clplumbing/Gmain_timeout.h>
#include <crm/crm.h>
#include <crm/msg_xml.h>
#include <crm/common/xml.h>
#include <crm/common/util.h>
#include <crm/dmalloc_wrapper.h>
#ifndef MAXLINE
# define MAXLINE 512
#endif
static uint ref_counter = 0;
gboolean crm_assert_failed = FALSE;
unsigned int crm_log_level = LOG_INFO;
void crm_set_env_options(void);
char *
generateReference(const char *custom1, const char *custom2)
{
const char *local_cust1 = custom1;
const char *local_cust2 = custom2;
int reference_len = 4;
char *since_epoch = NULL;
reference_len += 20; /* too big */
reference_len += 40; /* too big */
if(local_cust1 == NULL) { local_cust1 = "_empty_"; }
reference_len += strlen(local_cust1);
if(local_cust2 == NULL) { local_cust2 = "_empty_"; }
reference_len += strlen(local_cust2);
crm_malloc0(since_epoch, reference_len*(sizeof(char)));
if(since_epoch != NULL) {
sprintf(since_epoch, "%s-%s-%ld-%u",
local_cust1, local_cust2,
(unsigned long)time(NULL), ref_counter++);
}
return since_epoch;
}
gboolean
decodeNVpair(const char *srcstring, char separator, char **name, char **value)
{
int lpc = 0;
int len = 0;
const char *temp = NULL;
crm_debug_4("Attempting to decode: [%s]", srcstring);
if (srcstring != NULL) {
len = strlen(srcstring);
while(lpc <= len) {
if (srcstring[lpc] == separator
|| srcstring[lpc] == '\0') {
crm_malloc0(*name, sizeof(char)*lpc+1);
if(*name == NULL) {
break; /* and return FALSE */
}
strncpy(*name, srcstring, lpc);
(*name)[lpc] = '\0';
/* this sucks but as the strtok manpage says..
* it *is* a bug
*/
len = len-lpc; len--;
if(len <= 0) {
*value = NULL;
} else {
crm_malloc0(*value, sizeof(char)*len+1);
if(*value == NULL) {
crm_free(*name);
break; /* and return FALSE */
}
temp = srcstring+lpc+1;
strncpy(*value, temp, len);
(*value)[len] = '\0';
}
return TRUE;
}
lpc++;
}
}
*name = NULL;
*value = NULL;
return FALSE;
}
+char *
+crm_concat(const char *prefix, const char *suffix, char join)
+{
+ int len = 0;
+ char *new_str = NULL;
+ CRM_ASSERT(prefix != NULL);
+ CRM_ASSERT(suffix != NULL);
+ len = strlen(prefix) + strlen(suffix) + 2;
+
+ crm_malloc0(new_str, sizeof(char)*(len));
+ sprintf(new_str, "%s%c%s", prefix, join, suffix);
+ new_str[len-1] = 0;
+ return new_str;
+}
+
+
char *
generate_hash_key(const char *crm_msg_reference, const char *sys)
{
- int ref_len = strlen(sys?sys:"none") + strlen(crm_msg_reference) + 2;
- char *hash_key = NULL;
- crm_malloc0(hash_key, sizeof(char)*(ref_len));
-
- if(hash_key != NULL) {
- sprintf(hash_key, "%s_%s", sys?sys:"none", crm_msg_reference);
- hash_key[ref_len-1] = '\0';
- crm_debug_3("created hash key: (%s)", hash_key);
- }
+ char *hash_key = crm_concat(sys?sys:"none", crm_msg_reference, '_');
+ crm_debug_3("created hash key: (%s)", hash_key);
return hash_key;
}
char *
generate_hash_value(const char *src_node, const char *src_subsys)
{
- int ref_len;
char *hash_value = NULL;
if (src_node == NULL || src_subsys == NULL) {
return NULL;
}
if (strcmp(CRM_SYSTEM_DC, src_subsys) == 0) {
hash_value = crm_strdup(src_subsys);
if (!hash_value) {
crm_err("memory allocation failed in "
"generate_hash_value()");
- return NULL;
}
return hash_value;
}
-
- ref_len = strlen(src_subsys) + strlen(src_node) + 2;
- crm_malloc0(hash_value, sizeof(char)*(ref_len));
- if (!hash_value) {
- crm_err("memory allocation failed in "
- "generate_hash_value()");
- return NULL;
- }
-
- snprintf(hash_value, ref_len-1, "%s_%s", src_node, src_subsys);
- hash_value[ref_len-1] = '\0';/* make sure it is null terminated */
+ hash_value = crm_concat(src_node, src_subsys, '_');
crm_info("created hash value: (%s)", hash_value);
return hash_value;
}
gboolean
decode_hash_value(gpointer value, char **node, char **subsys)
{
char *char_value = (char*)value;
int value_len = strlen(char_value);
crm_info("Decoding hash value: (%s:%d)", char_value, value_len);
if (strcmp(CRM_SYSTEM_DC, (char*)value) == 0) {
*node = NULL;
*subsys = (char*)crm_strdup(char_value);
if (*subsys == NULL) {
crm_err("memory allocation failed in "
"decode_hash_value()");
return FALSE;
}
crm_info("Decoded value: (%s:%d)", *subsys,
(int)strlen(*subsys));
return TRUE;
} else if (char_value != NULL) {
if (decodeNVpair(char_value, '_', node, subsys)) {
return TRUE;
} else {
*node = NULL;
*subsys = NULL;
return FALSE;
}
}
return FALSE;
}
char *
crm_itoa(int an_int)
{
int len = 32;
char *buffer = NULL;
crm_malloc0(buffer, sizeof(char)*(len+1));
if(buffer != NULL) {
snprintf(buffer, len, "%d", an_int);
}
return buffer;
}
extern int LogToLoggingDaemon(int priority, const char * buf, int bstrlen, gboolean use_pri_str);
gboolean
crm_log_init(const char *entity)
{
/* const char *test = "Testing log daemon connection"; */
/* Redirect messages from glib functions to our handler */
/* cl_malloc_forced_for_glib(); */
g_log_set_handler(NULL,
G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL
| G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE
| G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG
| G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL,
cl_glib_msg_handler, NULL);
/* and for good measure... - this enum is a bit field (!) */
g_log_set_always_fatal((GLogLevelFlags)0); /*value out of range*/
cl_log_set_entity(entity);
cl_log_set_facility(LOG_LOCAL7);
cl_set_corerootdir(HA_COREDIR);
cl_cdtocoredir();
crm_set_env_options();
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
return TRUE;
}
/* returns the old value */
unsigned int
set_crm_log_level(unsigned int level)
{
unsigned int old = crm_log_level;
while(crm_log_level < level) {
alter_debug(DEBUG_INC);
}
while(crm_log_level > level) {
alter_debug(DEBUG_DEC);
}
return old;
}
unsigned int
get_crm_log_level(void)
{
return crm_log_level;
}
void
crm_log_message_adv(int level, const char *prefix, const HA_Message *msg)
{
if((int)crm_log_level >= level) {
do_crm_log(level, NULL, NULL, "#========= %s message start ==========#", prefix?prefix:"");
if(level > LOG_DEBUG) {
cl_log_message(LOG_DEBUG, msg);
} else {
cl_log_message(level, msg);
}
}
}
void
do_crm_log(int log_level, const char *file, const char *function,
const char *fmt, ...)
{
int log_as = log_level;
gboolean do_log = FALSE;
if(log_level <= (int)crm_log_level) {
do_log = TRUE;
if(log_level > LOG_INFO) {
log_as = LOG_DEBUG;
}
}
if(do_log) {
va_list ap;
int nbytes;
char buf[MAXLINE];
va_start(ap, fmt);
nbytes=vsnprintf(buf, MAXLINE, fmt, ap);
va_end(ap);
log_level -= LOG_INFO;
if(log_level > 1) {
if(file == NULL && function == NULL) {
cl_log(log_as, "[%d] %s", log_level, buf);
} else {
cl_log(log_as, "mask(%s%s%s [%d]): %s",
file?file:"",
(file !=NULL && function !=NULL)?":":"",
function?function:"", log_level, buf);
}
} else {
if(file == NULL && function == NULL) {
cl_log(log_as, "%s", buf);
} else {
cl_log(log_as, "mask(%s%s%s): %s",
file?file:"",
(file !=NULL && function !=NULL)?":":"",
function?function:"", buf);
}
}
if(nbytes > MAXLINE) {
cl_log(LOG_WARNING, "Log from %s() was truncated",
crm_str(function));
}
}
}
int
compare_version(const char *version1, const char *version2)
{
int lpc = 0;
char *step1 = NULL, *step2 = NULL;
char *rest1 = NULL, *rest2 = NULL;
if(version1 == NULL && version2 == NULL) {
return 0;
} else if(version1 == NULL) {
return -1;
} else if(version2 == NULL) {
return 1;
}
if(version1 != NULL) {
rest1 = crm_strdup(version1);
} else {
version1 = "<null>";
}
if(version2 != NULL) {
rest2 = crm_strdup(version2);
} else {
version2 = "<null>";
}
while(1) {
int cmp = 0;
int step1_i = 0;
int step2_i = 0;
char *tmp1 = NULL, *tmp2 = NULL;
decodeNVpair(rest1, '.', &step1, &tmp1);
decodeNVpair(rest2, '.', &step2, &tmp2);
if(step1 != NULL) {
step1_i = atoi(step1);
}
if(step2 != NULL) {
step2_i = atoi(step2);
}
if(step1_i < step2_i){
cmp = -1;
} else if (step1_i > step2_i){
cmp = 1;
}
crm_debug_4("compare[%d (%d)]: %d(%s) %d(%s)",
lpc++, cmp,
step1_i, crm_str(step1),
step2_i, crm_str(step2));
crm_free(rest1);
crm_free(rest2);
rest1 = tmp1;
rest2 = tmp2;
if(step1 == NULL && step2 == NULL) {
break;
}
crm_free(step1);
crm_free(step2);
if(cmp < 0) {
crm_debug_2("%s < %s", version1, version2);
return -1;
} else if(cmp > 0) {
crm_debug_2("%s > %s", version1, version2);
return 1;
}
}
crm_debug_2("%s == %s", version1, version2);
return 0;
}
gboolean do_stderr = FALSE;
void
alter_debug(int nsig)
{
CL_SIGNAL(DEBUG_INC, alter_debug);
CL_SIGNAL(DEBUG_DEC, alter_debug);
switch(nsig) {
case DEBUG_INC:
crm_log_level++;
crm_debug("Upped log level to %d", crm_log_level);
break;
case DEBUG_DEC:
crm_log_level--;
crm_debug("Reduced log level to %d", crm_log_level);
break;
default:
fprintf(stderr, "Unknown signal %d\n", nsig);
cl_log(LOG_ERR, "Unknown signal %d", nsig);
break;
}
}
void g_hash_destroy_str(gpointer data)
{
crm_free(data);
}
gboolean
safe_str_eq(const char *a, const char *b)
{
if(a == b) {
return TRUE;
} else if(a == NULL || b == NULL) {
return FALSE;
} else if(strcmp(a, b) == 0) {
return TRUE;
}
return FALSE;
}
gboolean
safe_str_neq(const char *a, const char *b)
{
if(a == b) {
return FALSE;
} else if(a==NULL || b==NULL) {
return TRUE;
} else if(strcmp(a, b) == 0) {
return FALSE;
}
return TRUE;
}
char *
crm_strdup(const char *a)
{
char *ret = NULL;
CRM_DEV_ASSERT(a != NULL);
if(a != NULL) {
ret = cl_strdup(a);
} else {
crm_warn("Cannot dup NULL string");
}
return ret;
}
static GHashTable *crm_uuid_cache = NULL;
void
set_uuid(ll_cluster_t *hb,crm_data_t *node,const char *attr,const char *uname)
{
char *uuid_calc = NULL;
if(crm_uuid_cache == NULL) {
crm_uuid_cache = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
}
CRM_DEV_ASSERT(uname != NULL);
/* avoid blocking calls where possible */
uuid_calc = g_hash_table_lookup(crm_uuid_cache, uname);
if(uuid_calc != NULL) {
crm_xml_add(node, attr, uuid_calc);
return;
}
crm_malloc0(uuid_calc, sizeof(char)*50);
if(uuid_calc != NULL) {
cl_uuid_t uuid_raw;
if(hb->llc_ops->get_uuid_by_name(
hb, uname, &uuid_raw) == HA_FAIL) {
crm_err("Could not calculate UUID for %s", uname);
crm_free(uuid_calc);
uuid_calc = crm_strdup(uname);
} else {
cl_uuid_unparse(&uuid_raw, uuid_calc);
g_hash_table_insert(
crm_uuid_cache,
crm_strdup(uname), crm_strdup(uuid_calc));
}
crm_xml_add(node, attr, uuid_calc);
}
crm_free(uuid_calc);
}/*memory leak*/ /* BEAM BUG - this is not a memory leak */
void
crm_set_ha_options(ll_cluster_t *hb_cluster)
{
#if 0
int facility;
char *param_val = NULL;
const char *param_name = NULL;
if(hb_cluster == NULL) {
crm_set_env_options();
return;
}
/* change the logging facility to the one used by heartbeat daemon */
crm_debug("Switching to Heartbeat logger");
if (( facility =
hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) {
cl_log_set_facility(facility);
}
crm_debug_2("Facility: %d", facility);
param_name = KEY_LOGFILE;
param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name);
crm_debug_3("%s = %s", param_name, param_val);
if(param_val != NULL) {
cl_log_set_logfile(param_val);
cl_free(param_val);
param_val = NULL;
}
param_name = KEY_DBGFILE;
param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name);
crm_debug_3("%s = %s", param_name, param_val);
if(param_val != NULL) {
cl_log_set_debugfile(param_val);
cl_free(param_val);
param_val = NULL;
}
param_name = KEY_DEBUGLEVEL;
param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name);
crm_debug_3("%s = %s", param_name, param_val);
if(param_val != NULL) {
int debug_level = atoi(param_val);
if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) {
set_crm_log_level(LOG_INFO + debug_level);
}
cl_free(param_val);
param_val = NULL;
}
param_name = KEY_LOGDAEMON;
param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name);
crm_debug_3("%s = %s", param_name, param_val);
if(param_val != NULL) {
int uselogd;
cl_str_to_boolean(param_val, &uselogd);
cl_log_set_uselogd(uselogd);
if(cl_log_get_uselogd()) {
cl_set_logging_wqueue_maxlen(500);
}
cl_free(param_val);
param_val = NULL;
}
param_name = KEY_CONNINTVAL;
param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name);
crm_debug_3("%s = %s", param_name, param_val);
if(param_val != NULL) {
int logdtime;
logdtime = crm_get_msec(param_val);
cl_log_set_logdtime(logdtime);
cl_free(param_val);
param_val = NULL;
}
#endif
}
#define ENV_PREFIX "HA_"
void
crm_set_env_options(void)
{
char *param_val = NULL;
const char *param_name = NULL;
/* apparently we're not allowed to free the result of getenv */
param_name = ENV_PREFIX "" KEY_DEBUGLEVEL;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
int debug_level = atoi(param_val);
if(debug_level > 0 && (debug_level+LOG_INFO) > (int)crm_log_level) {
set_crm_log_level(LOG_INFO + debug_level);
}
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_FACILITY;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
int facility = cl_syslogfac_str2int(param_val);
if(facility > 0) {
cl_log_set_facility(facility);
}
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_LOGFILE;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
if(safe_str_eq("/dev/null", param_val)) {
param_val = NULL;
}
cl_log_set_logfile(param_val);
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_DBGFILE;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
if(safe_str_eq("/dev/null", param_val)) {
param_val = NULL;
}
cl_log_set_debugfile(param_val);
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_LOGDAEMON;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
int uselogd;
cl_str_to_boolean(param_val, &uselogd);
cl_log_set_uselogd(uselogd);
if(uselogd) {
cl_set_logging_wqueue_maxlen(500);
cl_log_set_logd_channel_source(NULL, NULL);
}
param_val = NULL;
}
param_name = ENV_PREFIX "" KEY_CONNINTVAL;
param_val = getenv(param_name);
crm_debug("%s = %s", param_name, param_val);
if(param_val != NULL) {
int logdtime;
logdtime = crm_get_msec(param_val);
cl_log_set_logdtime(logdtime);
param_val = NULL;
}
}
gboolean
crm_is_true(const char * s)
{
gboolean ret = FALSE;
if(s != NULL) {
cl_str_to_boolean(s, &ret);
}
return ret;
}
int
crm_str_to_boolean(const char * s, int * ret)
{
if(s == NULL) {
return -1;
} else if (strcasecmp(s, "true") == 0
|| strcasecmp(s, "on") == 0
|| strcasecmp(s, "yes") == 0
|| strcasecmp(s, "y") == 0
|| strcasecmp(s, "1") == 0){
*ret = TRUE;
return 1;
} else if (strcasecmp(s, "false") == 0
|| strcasecmp(s, "off") == 0
|| strcasecmp(s, "no") == 0
|| strcasecmp(s, "n") == 0
|| strcasecmp(s, "0") == 0){
*ret = FALSE;
return 1;
}
return -1;
}
#ifndef NUMCHARS
# define NUMCHARS "0123456789."
#endif
#ifndef WHITESPACE
# define WHITESPACE " \t\n\r\f"
#endif
long
crm_get_msec(const char * input)
{
const char * cp = input;
const char * units;
long multiplier = 1000;
long divisor = 1;
long ret = -1;
double dret;
if(input == NULL) {
return 0;
}
cp += strspn(cp, WHITESPACE);
units = cp + strspn(cp, NUMCHARS);
units += strspn(units, WHITESPACE);
if (strchr(NUMCHARS, *cp) == NULL) {
return ret;
}
if (strncasecmp(units, "ms", 2) == 0
|| strncasecmp(units, "msec", 4) == 0) {
multiplier = 1;
divisor = 1;
}else if (strncasecmp(units, "us", 2) == 0
|| strncasecmp(units, "usec", 4) == 0) {
multiplier = 1;
divisor = 1000;
}else if (strncasecmp(units, "s", 1) == 0
|| strncasecmp(units, "sec", 3) == 0) {
multiplier = 1000;
divisor = 1;
}else if (strncasecmp(units, "m", 1) == 0
|| strncasecmp(units, "min", 3) == 0) {
multiplier = 60*1000;
divisor = 1;
}else if (*units != EOS && *units != '\n'
&& *units != '\r') {
return ret;
}
dret = atof(cp);
dret *= (double)multiplier;
dret /= (double)divisor;
dret += 0.5;
ret = (long)dret;
return(ret);
}
gboolean
ccm_have_quorum(oc_ed_t event)
{
if(event==OC_EV_MS_NEW_MEMBERSHIP) {
return TRUE;
}
return FALSE;
}
const char *
ccm_event_name(oc_ed_t event)
{
if(event==OC_EV_MS_NEW_MEMBERSHIP) {
return "NEW MEMBERSHIP";
} else if(event==OC_EV_MS_NOT_PRIMARY) {
return "NOT PRIMARY";
} else if(event==OC_EV_MS_PRIMARY_RESTORED) {
return "PRIMARY RESTORED";
} else if(event==OC_EV_MS_EVICTED) {
return "EVICTED";
} else if(event==OC_EV_MS_INVALID) {
return "INVALID";
}
return "NO QUORUM MEMBERSHIP";
}
const char *
op_status2text(op_status_t status)
{
switch(status) {
case LRM_OP_PENDING:
return "pending";
break;
case LRM_OP_DONE:
return "complete";
break;
case LRM_OP_ERROR:
return "ERROR";
break;
case LRM_OP_TIMEOUT:
return "TIMED OUT";
break;
case LRM_OP_NOTSUPPORTED:
return "NOT SUPPORTED";
break;
case LRM_OP_CANCELLED:
return "cancelled";
break;
}
CRM_DEV_ASSERT(status >= LRM_OP_PENDING && status <= LRM_OP_CANCELLED);
crm_err("Unknown status: %d", status);
return "UNKNOWN!";
}
char *
generate_op_key(const char *rsc_id, const char *op_type, int interval)
{
int len = 35;
char *op_id = NULL;
CRM_DEV_ASSERT(rsc_id != NULL); if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(op_type != NULL); if(crm_assert_failed) { return NULL; }
len += strlen(op_type);
len += strlen(rsc_id);
crm_malloc0(op_id, sizeof(char)*len);
if(op_id != NULL) {
sprintf(op_id, "%s_%s_%d", rsc_id, op_type, interval);
}
return op_id;
}
char *
generate_notify_key(const char *rsc_id, const char *notify_type, const char *op_type)
{
int len = 12;
char *op_id = NULL;
CRM_DEV_ASSERT(rsc_id != NULL); if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(op_type != NULL); if(crm_assert_failed) { return NULL; }
CRM_DEV_ASSERT(notify_type != NULL); if(crm_assert_failed) { return NULL; }
len += strlen(op_type);
len += strlen(rsc_id);
len += strlen(notify_type);
crm_malloc0(op_id, sizeof(char)*len);
if(op_id != NULL) {
sprintf(op_id, "%s_%s_notify_%s_0", rsc_id, notify_type, op_type);
}
return op_id;
}
char *
generate_transition_magic(const char *transition_key, int op_status)
{
int len = 40;
char *fail_state = NULL;
CRM_DEV_ASSERT(transition_key != NULL);
if(crm_assert_failed) { return NULL; }
len += strlen(transition_key);
crm_malloc0(fail_state, sizeof(char)*len);
if(fail_state != NULL) {
snprintf(fail_state, len, "%d:%s", op_status, transition_key);
}
return fail_state;
}
gboolean
decode_transition_magic(
const char *magic, char **uuid, int *transition_id, int *op_status)
{
char *key = NULL;
char *status = NULL;
if(decodeNVpair(magic, ':', &status, &key) == FALSE) {
return FALSE;
}
if(decode_transition_key(key, uuid, transition_id) == FALSE) {
return FALSE;
}
*op_status = atoi(status);
crm_free(key);
crm_free(status);
return TRUE;
}
char *
generate_transition_key(int transition_id, const char *node)
{
int len = 40;
char *fail_state = NULL;
CRM_DEV_ASSERT(node != NULL); if(crm_assert_failed) { return NULL; }
len += strlen(node);
crm_malloc0(fail_state, sizeof(char)*len);
if(fail_state != NULL) {
snprintf(fail_state, len, "%d:%s", transition_id, node);
}
return fail_state;
}
gboolean
decode_transition_key(const char *key, char **uuid, int *transition_id)
{
char *transition = NULL;
if(decodeNVpair(key, ':', &transition, uuid) == FALSE) {
return FALSE;
}
*transition_id = atoi(transition);
crm_free(transition);
return TRUE;
}
gboolean
crm_mem_stats(volatile cl_mem_stats_t *mem_stats)
{
volatile cl_mem_stats_t *active_stats = mem_stats;
if(active_stats == NULL) {
active_stats = cl_malloc_getstats();
}
CRM_DEV_ASSERT(active_stats != NULL);
#ifndef CRM_USE_MALLOC
if(active_stats->numalloc > active_stats->numfree) {
crm_err("Potential memory leak detected:"
" %lu alloc's vs. %lu free's (%lu)"
" (%lu bytes not freed: req=%lu, alloc'd=%lu)",
active_stats->numalloc, active_stats->numfree,
active_stats->numalloc - active_stats->numfree,
active_stats->nbytes_alloc, active_stats->nbytes_req,
active_stats->mallocbytes);
return TRUE;
} else if(active_stats->numalloc < active_stats->numfree) {
crm_debug("Process shrank: %lu alloc's vs. %lu free's (%lu)",
active_stats->numalloc, active_stats->numfree,
active_stats->numalloc - active_stats->numfree);
}
#endif
return FALSE;
}
void
crm_zero_mem_stats(volatile cl_mem_stats_t *stats)
{
volatile cl_mem_stats_t *active_stats = NULL;
if(stats != NULL) {
cl_malloc_setstats(stats);
}
active_stats = cl_malloc_getstats();
active_stats->numalloc = 0;
active_stats->numfree = 0;
active_stats->numrealloc = 0;
active_stats->nbytes_req = 0;
active_stats->nbytes_alloc = 0;
active_stats->mallocbytes = 0;
active_stats->arena = 0;
}
diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c
index 868ab21eeb..67f6de0fa5 100644
--- a/lib/crm/common/xml.c
+++ b/lib/crm/common/xml.c
@@ -1,2006 +1,2129 @@
-/* $Id: xml.c,v 1.30 2005/09/08 09:49:18 andrew Exp $ */
+/* $Id: xml.c,v 1.31 2005/09/12 11:00:19 andrew 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>
int is_comment_start(const char *input);
int is_comment_end(const char *input);
gboolean drop_comments(const char *input, int *offset);
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 {
const char *new_value = NULL;
crm_validate_data(node);
ha_msg_mod(node, name, value);
new_value = crm_element_value(node, name);
CRM_DEV_ASSERT(cl_is_allocated(new_value));
return new_value;
}
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 '\r':
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_DEV_ASSERT(filename != NULL);
crm_debug_3("Writing XML out to %s", filename);
crm_validate_data(xml_node);
if (xml_node == NULL) {
crm_err("Cannot write NULL to %s", filename);
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");
if(file_output_strm == NULL) {
res = -1;
cl_perror("Cannot write to %s", filename);
} else {
char *buffer = dump_xml_formatted(xml_node);
CRM_DEV_ASSERT(buffer != NULL && strlen(buffer) > 0);
if(buffer != NULL && strlen(buffer) > 0) {
res = fprintf(file_output_strm, "%s", buffer);
if(res < 0) {
cl_perror("Cannot write output to %s",
filename);
}
}
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);
log_data_element(function, text, 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;
crm_malloc0(buffer, 3*get_stringlen(an_xml_node));
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;
crm_malloc0(buffer, 2*get_stringlen(an_xml_node));
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;
}
int
is_comment_start(const char *input)
{
CRM_DEV_ASSERT(input != NULL);
if(crm_assert_failed) {
return 0;
}
if(strlen(input) > 4
&& input[0] == '<'
&& input[1] == '!'
&& input[2] == '-'
&& input[3] == '-') {
crm_debug_6("Found comment start: <!--");
return 4;
} else if(strlen(input) > 2
&& input[0] == '<'
&& input[1] == '!') {
crm_debug_6("Found comment start: <!");
return 2;
} else if(strlen(input) > 2
&& input[0] == '<'
&& input[1] == '?') {
crm_debug_6("Found comment start: <?");
return 2;
}
if(strlen(input) > 3) {
crm_debug_6("Not comment start: %c%c%c%c", input[0], input[1], input[2], input[3]);
} else {
crm_debug_6("Not comment start");
}
return 0;
}
int
is_comment_end(const char *input)
{
CRM_DEV_ASSERT(input != NULL);
if(crm_assert_failed) {
return 0;
}
if(strlen(input) > 2
&& input[0] == '-'
&& input[1] == '-'
&& input[2] == '>') {
crm_debug_6("Found comment end: -->");
return 3;
} else if(strlen(input) > 1
&& input[0] == '?'
&& input[1] == '>') {
crm_debug_6("Found comment end: ?>");
return 2;
}
if(strlen(input) > 2) {
crm_debug_6("Not comment end: %c%c%c", input[0], input[1], input[2]);
} else {
crm_debug_6("Not comment end");
}
return 0;
}
gboolean
drop_comments(const char *input, int *offset)
{
gboolean more = TRUE;
gboolean in_directive = FALSE;
int in_comment = FALSE;
const char *our_input = input;
int len = 0, lpc = 0;
int tag_len = 0;
char ch = 0;
if(input == NULL) {
return FALSE;
}
if(offset != NULL) {
our_input = input + (*offset);
}
len = strlen(our_input);
while(lpc < len && more) {
ch = our_input[lpc];
crm_debug_6("Processing char %c[%d]", ch, lpc);
switch(ch) {
case 0:
if(in_comment == FALSE) {
more = FALSE;
} else {
crm_err("unexpected EOS");
crm_warn("Parsing error at or before: %s", our_input);
}
break;
case '<':
tag_len = is_comment_start(our_input + lpc);
if(tag_len > 0) {
if(in_comment) {
crm_err("Nested XML comments are not supported!");
crm_warn("Parsing error at or before: %s", our_input);
crm_warn("Netsed comment found at: %s", our_input + lpc + tag_len);
}
in_comment = TRUE;
lpc+=tag_len;
if(tag_len == 2) {
#if 1
if(our_input[lpc-1] == '!') {
in_directive = TRUE;
}
#else
tag_len = get_tag_name(our_input + lpc);
crm_debug_2("Tag length: %d", len);
if(strncmp("DOCTYPE", our_input+lpc, tag_len) == 0) {
in_directive = TRUE;
}
#endif
}
} else if(in_comment == FALSE){
more = FALSE;
} else {
lpc++;
crm_debug_6("Skipping comment char %c", our_input[lpc]);
}
break;
case '>':
lpc++;
if(in_directive) {
in_directive = FALSE;
in_comment = FALSE;
}
break;
case '-':
case '?':
tag_len = is_comment_end(our_input + lpc);
if(tag_len > 0) {
lpc+=tag_len;
in_comment = FALSE;
} else {
lpc++;
crm_debug_6("Skipping comment char %c", our_input[lpc]);
}
break;
case ' ':
case '\t':
case '\n':
case '\r':
lpc++;
crm_debug_6("Skipping whitespace char %d", our_input[lpc]);
break;
default:
lpc++;
crm_debug_6("Skipping comment char %c", our_input[lpc]);
break;
}
}
crm_debug_4("Finished processing comments");
if(offset != NULL) {
(*offset) += lpc;
}
if(lpc > 0) {
crm_debug_5("Skipped %d comment chars", lpc);
return TRUE;
}
return FALSE;
}
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;
gboolean were_comments = 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 && were_comments) {
were_comments = drop_comments(our_input, &lpc);
}
CRM_DEV_ASSERT(our_input[lpc] == '<');
if(crm_assert_failed) {
return NULL;
}
lpc++;
len = get_tag_name(our_input + lpc);
crm_debug_5("Tag length: %d", len);
if(len < 0) {
return NULL;
}
crm_malloc0(tag_name, len+1);
strncpy(tag_name, our_input + lpc, 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;
gboolean any_comments = FALSE;
do {
were_comments = drop_comments(our_input, &lpc);
any_comments = any_comments || were_comments;
} while(lpc < len && were_comments);
if(any_comments) {
lpc--;
break;
}
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);
if(our_input[lpc] == '<') {
/* lpc is about to get incrimented
* make sure we process the '<' that
* we're currently looking at
*/
lpc--;
}
/* 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':
case '\r':
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(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_4("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_4("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_5("\t%s: %s", crm_str(prop_name),
crm_str(left_value));
} else if(safe_str_eq(left_value, right_val)) {
crm_debug_4("\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_4("\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_4("\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;
}
GHashTable *
xml2list(crm_data_t *parent)
{
crm_data_t *nvpair_list = NULL;
GHashTable *nvpair_hash = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
CRM_DEV_ASSERT(parent != NULL);
if(parent != NULL) {
nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE);
if(nvpair_list == NULL) {
crm_debug("No attributes in %s",
crm_element_name(parent));
crm_log_xml_debug_2(parent,"No attributes for resource op");
}
}
xml_child_iter(
nvpair_list, node_iter, XML_CIB_TAG_NVPAIR,
const char *key = crm_element_value(
node_iter, XML_NVPAIR_ATTR_NAME);
const char *value = crm_element_value(
node_iter, XML_NVPAIR_ATTR_VALUE);
crm_debug_2("Added %s=%s", key, value);
g_hash_table_insert(
nvpair_hash, crm_strdup(key), crm_strdup(value));
);
return nvpair_hash;
}
+
+
+static void
+assign_uuid(crm_data_t *xml_obj)
+{
+ cl_uuid_t new_uuid;
+ char *new_uuid_s = NULL;
+ const char *new_uuid_s2 = NULL;
+
+ crm_malloc0(new_uuid_s, sizeof(char)*38);
+ cl_uuid_generate(&new_uuid);
+ cl_uuid_unparse(&new_uuid, new_uuid_s);
+
+ new_uuid_s2 = crm_xml_add(xml_obj, XML_ATTR_ID, new_uuid_s);
+ crm_log_xml_warn(xml_obj, "Updated object");
+
+ CRM_DEV_ASSERT(cl_is_allocated(new_uuid_s));
+ CRM_DEV_ASSERT(cl_is_allocated(new_uuid_s2));
+
+ crm_free(new_uuid_s);
+
+ CRM_DEV_ASSERT(cl_is_allocated(new_uuid_s2));
+}
+
+void
+do_id_check(crm_data_t *xml_obj, GHashTable *id_hash)
+{
+ int lpc = 0;
+ char *lookup_id = NULL;
+
+ const char *tag_id = NULL;
+ const char *tag_name = NULL;
+ const char *lookup_value = NULL;
+
+ gboolean created_hash = FALSE;
+
+ const char *allowed_list[] = {
+ XML_TAG_CIB,
+ XML_CIB_TAG_NODES,
+ XML_CIB_TAG_RESOURCES,
+ XML_CIB_TAG_CONSTRAINTS,
+ XML_CIB_TAG_STATUS,
+ XML_CIB_TAG_LRM,
+ XML_LRM_TAG_RESOURCES,
+ "operations",
+ };
+
+ const char *non_unique[] = {
+ XML_LRM_TAG_RESOURCE,
+ XML_LRM_TAG_RSC_OP,
+ };
+
+ if(xml_obj == NULL) {
+ return;
+
+ } else if(id_hash == NULL) {
+ created_hash = TRUE;
+ id_hash = g_hash_table_new_full(
+ g_str_hash, g_str_equal,
+ g_hash_destroy_str, g_hash_destroy_str);
+ }
+
+ xml_child_iter(
+ xml_obj, xml_child, NULL,
+ do_id_check(xml_child, id_hash);
+ );
+
+ tag_id = ID(xml_obj);
+ tag_name = TYPE(xml_obj);
+
+ xml_prop_iter(
+ xml_obj, local_prop_name, local_prop_value,
+
+ if(ID(xml_obj) != NULL) {
+ for(lpc = 0; lpc < DIMOF(non_unique); lpc++) {
+ if(safe_str_eq(tag_name, non_unique[lpc])) {
+ /* this tag is never meant to have an ID */
+ break;
+ }
+ }
+ if(lpc < DIMOF(non_unique)) {
+ break;
+ }
+ lookup_id = crm_concat(tag_name, tag_id, '-');
+ lookup_value = g_hash_table_lookup(id_hash, lookup_id);
+ if(lookup_value != NULL) {
+ assign_uuid(xml_obj);
+ crm_err("\"id\" collision detected.");
+ crm_err(" Multiple %s entries with id=\"%s\","
+ " assigned id=\"%s\"",
+ tag_name, lookup_value, ID(xml_obj));
+ crm_free(lookup_id);
+ break;
+
+ } else {
+ g_hash_table_insert(
+ id_hash, lookup_id, crm_strdup(tag_id));
+ break;
+ }
+ }
+
+ for(lpc = 0; lpc < DIMOF(allowed_list); lpc++) {
+ if(safe_str_eq(tag_name, allowed_list[lpc])) {
+ /* this tag is never meant to have an ID */
+ break;
+ }
+ }
+ if(lpc < DIMOF(allowed_list)) {
+ break;
+ }
+ assign_uuid(xml_obj);
+ crm_err("Object with attributes but no ID field detected."
+ " Assigned: %s", ID(xml_obj));
+ break;
+
+ );
+
+ if(created_hash) {
+ g_hash_table_destroy(id_hash);
+ }
+
+}
+

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 10, 1:38 AM (20 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009554
Default Alt Text
(155 KB)

Event Timeline