Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F4638866
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
80 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/crm/common/Makefile.am b/lib/crm/common/Makefile.am
new file mode 100644
index 0000000000..214068e6d2
--- /dev/null
+++ b/lib/crm/common/Makefile.am
@@ -0,0 +1,50 @@
+#
+# Copyright (C) 2004 Andrew Beekhof
+#
+# 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
+# of the License, or (at your option) any later version.
+#
+# This program 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 program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \
+ -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl \
+ -I$(top_builddir)/linux-ha -I$(top_srcdir)/linux-ha \
+ -I$(top_builddir) -I$(top_srcdir)
+
+AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS)
+
+hadir = $(sysconfdir)/ha.d
+halibdir = $(libdir)/@HB_PKG@
+
+## libraries
+lib_LTLIBRARIES = libcrmcommon.la
+
+
+## binary progs
+halib_PROGRAMS =
+
+
+## SOURCES
+
+noinst_HEADERS =
+
+libcrmcommon_la_SOURCES = ipc.c msg.c utils.c xml.c ctrl.c
+libcrmcommon_la_LDFLAGS = -version-info 0:0:0
+
+clean-generic:
+ rm -f *.log *.debug *.xml *~
+
+install-exec-local:
+
+uninstall-local:
diff --git a/lib/crm/common/ctrl.c b/lib/crm/common/ctrl.c
new file mode 100644
index 0000000000..d2593cf541
--- /dev/null
+++ b/lib/crm/common/ctrl.c
@@ -0,0 +1,98 @@
+/* $Id: ctrl.c,v 1.1 2005/04/12 12:49:02 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 <sys/param.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <crm/crm.h>
+#include <crm/msg_xml.h>
+#include <crm/common/ctrl.h>
+
+#include <apphb.h>
+
+#include <clplumbing/cl_log.h>
+#include <clplumbing/Gmain_timeout.h>
+
+#include <crm/dmalloc_wrapper.h>
+
+
+static int wdt_interval_ms = 10000;
+
+
+
+void
+register_with_apphb(const char *client_name,
+ gboolean(*tickle_fn)(gpointer data))
+{
+ char app_instance[APPNAME_LEN];
+ int hb_intvl_ms = wdt_interval_ms * 2;
+ int rc = 0;
+
+ /* Register with apphb */
+ crm_info("Signing in with AppHb");
+ sprintf(app_instance, "%s_%ld", client_name, (long)getpid());
+
+ crm_info("Client %s registering with apphb", app_instance);
+
+ rc = apphb_register(client_name, app_instance);
+
+ if (rc < 0) {
+ cl_perror("%s registration failure", app_instance);
+ exit(1);
+ }
+
+ crm_devel("Client %s registered with apphb", app_instance);
+
+ crm_info("Client %s setting %d ms apphb heartbeat interval",
+ app_instance, hb_intvl_ms);
+ rc = apphb_setinterval(hb_intvl_ms);
+ if (rc < 0) {
+ cl_perror("%s setinterval failure", app_instance);
+ exit(2);
+ }
+
+ /* regularly tell apphb that we are alive */
+ crm_info("Setting up AppHb Heartbeat");
+ Gmain_timeout_add(wdt_interval_ms, tickle_fn, NULL);
+}
+
+
+gboolean
+tickle_apphb_template(gpointer data)
+{
+ char app_instance[APPNAME_LEN];
+ int rc = 0;
+ sprintf(app_instance, "%s_%ld", "our_system_name", (long)getpid());
+
+ rc = apphb_hb();
+ if (rc < 0) {
+ cl_perror("%s apphb_hb failure", app_instance);
+
+ exit(3);
+ }
+ return TRUE;
+}
diff --git a/lib/crm/common/ipc.c b/lib/crm/common/ipc.c
new file mode 100644
index 0000000000..1f64a9cfe4
--- /dev/null
+++ b/lib/crm/common/ipc.c
@@ -0,0 +1,383 @@
+/* $Id: ipc.c,v 1.1 2005/04/12 12:49:02 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 <sys/param.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <crm/crm.h>
+
+#include <clplumbing/ipc.h>
+#include <clplumbing/Gmain_timeout.h>
+#include <clplumbing/cl_log.h>
+#include <clplumbing/cl_signal.h>
+#include <clplumbing/lsb_exitcodes.h>
+#include <clplumbing/uids.h>
+#include <clplumbing/realtime.h>
+#include <clplumbing/GSource.h>
+#include <clplumbing/cl_poll.h>
+
+#ifdef USE_LIBXML
+# include <libxml/xmlmemory.h>
+# include <libxml/parser.h>
+# include <libxml/xpath.h>
+#endif
+
+#include <crm/common/ipc.h>
+#include <crm/msg_xml.h>
+#include <ha_msg.h>
+
+
+#include <crm/dmalloc_wrapper.h>
+
+gboolean
+send_ha_message(ll_cluster_t *hb_conn, HA_Message *msg, const char *node)
+{
+ gboolean all_is_good = TRUE;
+
+ if (msg == NULL) {
+ crm_err("cant send NULL message");
+ all_is_good = FALSE;
+
+ } else if(hb_conn == NULL) {
+ crm_err("No heartbeat connection specified");
+ all_is_good = FALSE;
+
+ } else if(hb_conn->llc_ops->chan_is_connected(hb_conn) != HA_OK) {
+ crm_err("Not connected to Heartbeat");
+ all_is_good = FALSE;
+
+ } else if(node == NULL
+ && hb_conn->llc_ops->sendclustermsg(hb_conn, msg) != HA_OK) {
+ IPC_Channel *ipc = hb_conn->llc_ops->ipcchan(hb_conn);
+ all_is_good = FALSE;
+ crm_err("Broadcast Send failed");
+ CRM_DEV_ASSERT(ipc->send_queue->current_qlen < ipc->send_queue->max_qlen);
+
+ } else if(node != NULL
+ && hb_conn->llc_ops->send_ordered_nodemsg(
+ hb_conn, msg, node) != HA_OK) {
+ IPC_Channel *ipc = hb_conn->llc_ops->ipcchan(hb_conn);
+ all_is_good = FALSE;
+ crm_err("Send failed");
+ CRM_DEV_ASSERT(ipc->send_queue->current_qlen < ipc->send_queue->max_qlen);
+ }
+
+ crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"HA[outbound]",msg);
+ return all_is_good;
+}
+
+#define ipc_log(fmt...) do_crm_log(server?LOG_WARNING:LOG_ERR, __FUNCTION__, NULL, fmt)
+
+/* frees msg */
+gboolean
+crm_send_ipc_message(IPC_Channel *ipc_client, HA_Message *msg, gboolean server)
+{
+ gboolean all_is_good = TRUE;
+
+ if (msg == NULL) {
+ crm_err("cant send NULL message");
+ all_is_good = FALSE;
+
+ } else if (ipc_client == NULL) {
+ crm_err("cant send message without an IPC Channel");
+ all_is_good = FALSE;
+
+ } else if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) {
+ ipc_log("IPC Channel is not connected");
+ all_is_good = FALSE;
+ }
+
+ if(all_is_good && msg2ipcchan(msg, ipc_client) != HA_OK) {
+ ipc_log("Could not send IPC, message");
+ all_is_good = FALSE;
+
+ if(ipc_client->ops->get_chan_status(ipc_client) != IPC_CONNECT) {
+ ipc_log("IPC Channel is no longer connected");
+
+ } else if(server == FALSE) {
+ CRM_DEV_ASSERT(ipc_client->send_queue->current_qlen < ipc_client->send_queue->max_qlen);
+ }
+ }
+
+ crm_log_message_adv(all_is_good?LOG_MSG:LOG_WARNING,"IPC[outbound]",msg);
+ crm_msg_del(msg);
+
+ return all_is_good;
+}
+
+void
+default_ipc_connection_destroy(gpointer user_data)
+{
+ return;
+}
+
+int
+init_server_ipc_comms(
+ char *channel_name,
+ gboolean (*channel_client_connect)(IPC_Channel *newclient,gpointer user_data),
+ void (*channel_connection_destroy)(gpointer user_data))
+{
+ /* the clients wait channel is the other source of events.
+ * This source delivers the clients connection events.
+ * listen to this source at a relatively lower priority.
+ */
+
+ char commpath[SOCKET_LEN];
+ IPC_WaitConnection *wait_ch;
+
+ sprintf(commpath, WORKING_DIR "/%s", channel_name);
+
+ wait_ch = wait_channel_init(commpath);
+
+ if (wait_ch == NULL) {
+ return 1;
+ }
+
+ G_main_add_IPC_WaitConnection(
+ G_PRIORITY_LOW, wait_ch, NULL, FALSE,
+ channel_client_connect, channel_name,
+ channel_connection_destroy);
+
+ crm_devel("Listening on: %s", commpath);
+
+ return 0;
+}
+
+GCHSource*
+init_client_ipc_comms(const char *channel_name,
+ gboolean (*dispatch)(
+ IPC_Channel* source_data, gpointer user_data),
+ void *client_data, IPC_Channel **ch)
+{
+ IPC_Channel *a_ch = NULL;
+ GCHSource *the_source = NULL;
+ void *callback_data = client_data;
+
+ a_ch = init_client_ipc_comms_nodispatch(channel_name);
+ if(ch != NULL) {
+ *ch = a_ch;
+ if(callback_data == NULL) {
+ callback_data = a_ch;
+ }
+ }
+
+ if(a_ch == NULL) {
+ crm_err("Setup of client connection failed,"
+ " not adding channel to mainloop");
+
+ return NULL;
+ }
+
+ if(dispatch == NULL) {
+ crm_warn("No dispatch method specified..."
+ "maybe you meant init_client_ipc_comms_nodispatch()?");
+ } else {
+ crm_devel("Adding dispatch method to channel");
+
+ the_source = G_main_add_IPC_Channel(
+ G_PRIORITY_LOW, a_ch, FALSE, dispatch, callback_data,
+ default_ipc_connection_destroy);
+ }
+
+ return the_source;
+}
+
+IPC_Channel *
+init_client_ipc_comms_nodispatch(const char *channel_name)
+{
+ IPC_Channel *ch;
+ GHashTable *attrs;
+ static char path[] = IPC_PATH_ATTR;
+
+ char *commpath = NULL;
+ int local_socket_len = 2; /* 2 = '/' + '\0' */
+
+
+ local_socket_len += strlen(channel_name);
+ local_socket_len += strlen(WORKING_DIR);
+
+ crm_malloc(commpath, sizeof(char)*local_socket_len);
+ if(commpath != NULL) {
+ sprintf(commpath, WORKING_DIR "/%s", channel_name);
+ commpath[local_socket_len - 1] = '\0';
+ crm_devel("Attempting to talk on: %s", commpath);
+ }
+
+ attrs = g_hash_table_new(g_str_hash,g_str_equal);
+ g_hash_table_insert(attrs, path, commpath);
+
+ ch = ipc_channel_constructor(IPC_ANYTYPE, attrs);
+ g_hash_table_destroy(attrs);
+
+ if (ch == NULL) {
+ crm_err("Could not access channel on: %s", commpath);
+ return NULL;
+
+ } else if (ch->ops->initiate_connection(ch) != IPC_OK) {
+ crm_debug("Could not init comms on: %s", commpath);
+ return NULL;
+ }
+
+ ch->ops->set_recv_qlen(ch, 100);
+ ch->ops->set_send_qlen(ch, 100);
+/* ch->should_send_block = TRUE; */
+
+ crm_devel("Processing of %s complete", commpath);
+
+ return ch;
+}
+
+IPC_WaitConnection *
+wait_channel_init(char daemonsocket[])
+{
+ IPC_WaitConnection *wait_ch;
+ mode_t mask;
+ char path[] = IPC_PATH_ATTR;
+ GHashTable * attrs;
+
+
+ attrs = g_hash_table_new(g_str_hash,g_str_equal);
+ g_hash_table_insert(attrs, path, daemonsocket);
+
+ mask = umask(0);
+ wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs);
+ if (wait_ch == NULL) {
+ cl_perror("Can't create wait channel of type %s",
+ IPC_ANYTYPE);
+ exit(1);
+ }
+ mask = umask(mask);
+
+ g_hash_table_destroy(attrs);
+
+ return wait_ch;
+}
+
+longclock_t ipc_call_start = 0;
+longclock_t ipc_call_stop = 0;
+longclock_t ipc_call_diff = 0;
+int ipc_call_diff_ms = 0;
+
+gboolean
+subsystem_msg_dispatch(IPC_Channel *sender, void *user_data)
+{
+ int lpc = 0;
+ IPC_Message *msg = NULL;
+ ha_msg_input_t *new_input = NULL;
+ gboolean all_is_well = TRUE;
+ const char *sys_to;
+ const char *task;
+
+ while(sender->ops->is_message_pending(sender)) {
+ gboolean process = FALSE;
+ if (sender->ch_status == IPC_DISCONNECT) {
+ /* The message which was pending for us is that
+ * the IPC status is now IPC_DISCONNECT */
+ break;
+ }
+ if (sender->ops->recv(sender, &msg) != IPC_OK) {
+ perror("Receive failure:");
+ return !all_is_well;
+ }
+ if (msg == NULL) {
+ crm_err("No message this time");
+ continue;
+ }
+
+ lpc++;
+ new_input = new_ipc_msg_input(msg);
+ msg->msg_done(msg);
+ crm_log_message(LOG_MSG, new_input->msg);
+
+ sys_to = cl_get_string(new_input->msg, F_CRM_SYS_TO);
+ task = cl_get_string(new_input->msg, F_CRM_TASK);
+
+ if(safe_str_eq(task, CRM_OP_HELLO)) {
+ process = TRUE;
+
+ } else if(sys_to == NULL) {
+ crm_err("Value of %s was NULL!!", F_CRM_SYS_TO);
+
+ } else if(task == NULL) {
+ crm_err("Value of %s was NULL!!", F_CRM_TASK);
+
+ } else {
+ process = TRUE;
+ }
+
+ if(process){
+ gboolean (*process_function)
+ (HA_Message *msg, crm_data_t *data, IPC_Channel *sender) = NULL;
+ process_function = user_data;
+#ifdef MSG_LOG
+ crm_log_message_adv(
+ LOG_MSG, __FUNCTION__, new_input->msg);
+#endif
+ if(ipc_call_diff_max_ms > 0) {
+ ipc_call_start = time_longclock();
+ }
+ if(FALSE == process_function(
+ new_input->msg, new_input->xml, sender)) {
+ crm_warn("Received a message destined for %s"
+ " by mistake", sys_to);
+ }
+ if(ipc_call_diff_max_ms > 0) {
+ ipc_call_stop = time_longclock();
+ ipc_call_diff = sub_longclock(
+ ipc_call_start, ipc_call_stop);
+ ipc_call_diff_ms = longclockto_ms(
+ ipc_call_diff);
+ if(ipc_call_diff_ms > ipc_call_diff_max_ms) {
+ crm_err("%s took %dms to complete",
+ sys_to, ipc_call_diff_ms);
+ }
+ }
+ } else {
+#ifdef MSG_LOG
+ crm_log_message_adv(
+ LOG_ERR, NULL, new_input->msg);
+#endif
+ }
+
+ delete_ha_msg_input(new_input);
+ msg = NULL;
+ }
+
+ /* clean up after a break */
+ if(msg != NULL) {
+ msg->msg_done(msg);
+ }
+
+ crm_verbose("Processed %d messages", lpc);
+ if (sender->ch_status != IPC_CONNECT) {
+ crm_err("The server has left us: Shutting down...NOW");
+
+ exit(1); /* shutdown properly later */
+
+ return !all_is_well;
+ }
+ return all_is_well;
+}
+
diff --git a/lib/crm/common/msg.c b/lib/crm/common/msg.c
new file mode 100644
index 0000000000..56004e8a3e
--- /dev/null
+++ b/lib/crm/common/msg.c
@@ -0,0 +1,356 @@
+/* $Id: msg.c,v 1.1 2005/04/12 12:49:02 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 <sys/param.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <stdlib.h>
+
+#include <clplumbing/cl_log.h>
+#include <ha_msg.h>
+
+#include <time.h>
+
+#include <crm/crm.h>
+#include <crm/msg_xml.h>
+#include <crm/common/msg.h>
+#include <crm/common/ipc.h>
+
+#include <crm/dmalloc_wrapper.h>
+
+HA_Message *create_common_message(
+ HA_Message *original_request, crm_data_t *xml_response_data);
+
+
+crm_data_t*
+createPingAnswerFragment(const char *from, const char *status)
+{
+ crm_data_t *ping = NULL;
+
+
+ ping = create_xml_node(NULL, XML_CRM_TAG_PING);
+
+ set_xml_property_copy(ping, XML_PING_ATTR_STATUS, status);
+ set_xml_property_copy(ping, XML_PING_ATTR_SYSFROM, from);
+
+ return ping;
+}
+
+HA_Message *
+validate_crm_message(
+ HA_Message *msg, const char *sys, const char *uuid, const char *msg_type)
+{
+ const char *from = NULL;
+ const char *to = NULL;
+ const char *type = NULL;
+ const char *crm_msg_reference = NULL;
+ HA_Message *action = NULL;
+ const char *true_sys;
+
+
+ if (msg == NULL) {
+ return NULL;
+ }
+
+ from = cl_get_string(msg, F_CRM_SYS_FROM);
+ to = cl_get_string(msg, F_CRM_SYS_TO);
+ type = cl_get_string(msg, F_CRM_MSG_TYPE);
+
+ crm_msg_reference = cl_get_string(msg, XML_ATTR_REFERENCE);
+ action = msg;
+ true_sys = sys;
+
+ if (uuid != NULL) { true_sys = generate_hash_key(sys, uuid); }
+
+ if (to == NULL) {
+ crm_info("No sub-system defined.");
+ action = NULL;
+ } else if (true_sys != NULL && strcmp(to, true_sys) != 0) {
+ crm_devel("The message is not for this sub-system (%s != %s).",
+ to, true_sys);
+ action = NULL;
+ }
+
+ if (type == NULL) {
+ crm_info("No message type defined.");
+ return NULL;
+ } else if (msg_type != NULL && strcmp(msg_type, type) != 0) {
+ crm_info("Expecting a (%s) message but received a (%s).",
+ msg_type, type);
+ action = NULL;
+ }
+
+ if (crm_msg_reference == NULL) {
+ crm_info("No message crm_msg_reference defined.");
+ action = NULL;
+ }
+/*
+ if(action != NULL)
+ crm_devel(
+ "XML is valid and node with message type (%s) found.",
+ type);
+ crm_devel("Returning node (%s)", xmlGetNodePath(action));
+*/
+
+ return action;
+}
+
+
+void
+send_hello_message(IPC_Channel *ipc_client,
+ const char *uuid,
+ const char *client_name,
+ const char *major_version,
+ const char *minor_version)
+{
+ crm_data_t *hello_node = NULL;
+ HA_Message *hello = NULL;
+ if (uuid == NULL || strlen(uuid) == 0
+ || client_name == NULL || strlen(client_name) == 0
+ || major_version == NULL || strlen(major_version) == 0
+ || minor_version == NULL || strlen(minor_version) == 0) {
+ crm_err("Missing fields, Hello message will not be valid.");
+ return;
+ }
+
+ hello_node = create_xml_node(NULL, XML_TAG_OPTIONS);
+ set_xml_property_copy(hello_node, "major_version", major_version);
+ set_xml_property_copy(hello_node, "minor_version", minor_version);
+ set_xml_property_copy(hello_node, "client_name", client_name);
+ set_xml_property_copy(hello_node, "client_uuid", uuid);
+
+ crm_trace("creating hello message");
+ hello = create_request(
+ CRM_OP_HELLO, hello_node, NULL, NULL, client_name, uuid);
+
+ send_ipc_message(ipc_client, hello);
+ crm_trace("hello message sent");
+
+ free_xml(hello_node);
+}
+
+
+gboolean
+process_hello_message(crm_data_t *hello,
+ char **uuid,
+ char **client_name,
+ char **major_version,
+ char **minor_version)
+{
+ const char *local_uuid;
+ const char *local_client_name;
+ const char *local_major_version;
+ const char *local_minor_version;
+
+ *uuid = NULL;
+ *client_name = NULL;
+ *major_version = NULL;
+ *minor_version = NULL;
+
+ if(hello == NULL) {
+ return FALSE;
+ }
+
+ local_uuid = crm_element_value(hello, "client_uuid");
+ local_client_name = crm_element_value(hello, "client_name");
+ local_major_version = crm_element_value(hello, "major_version");
+ local_minor_version = crm_element_value(hello, "minor_version");
+
+ if (local_uuid == NULL || strlen(local_uuid) == 0) {
+ crm_err("Hello message was not valid (field %s not found)",
+ "uuid");
+ return FALSE;
+
+ } else if (local_client_name==NULL || strlen(local_client_name)==0){
+ crm_err("Hello message was not valid (field %s not found)",
+ "client name");
+ return FALSE;
+
+ } else if(local_major_version == NULL
+ || strlen(local_major_version) == 0){
+ crm_err("Hello message was not valid (field %s not found)",
+ "major version");
+ return FALSE;
+
+ } else if (local_minor_version == NULL
+ || strlen(local_minor_version) == 0){
+ crm_err("Hello message was not valid (field %s not found)",
+ "minor version");
+ return FALSE;
+ }
+
+ *uuid = crm_strdup(local_uuid);
+ *client_name = crm_strdup(local_client_name);
+ *major_version = crm_strdup(local_major_version);
+ *minor_version = crm_strdup(local_minor_version);
+
+ crm_devel("Hello message ok");
+ return TRUE;
+}
+
+HA_Message *
+create_request_adv(const char *task, crm_data_t *msg_data,
+ const char *host_to, const char *sys_to,
+ const char *sys_from, const char *uuid_from,
+ const char *origin)
+{
+ char *true_from = NULL;
+ HA_Message *request = NULL;
+ char *reference = generateReference(task, sys_from);
+
+ if (uuid_from != NULL) {
+ true_from = generate_hash_key(sys_from, uuid_from);
+ } else if(sys_from != NULL) {
+ true_from = crm_strdup(sys_from);
+ } else {
+ crm_err("No sys from specified");
+ }
+
+ /* host_from will get set for us if necessary by CRMd when routed */
+ request = ha_msg_new(11);
+
+ ha_msg_add(request, F_CRM_ORIGIN, origin);
+ ha_msg_add(request, F_TYPE, T_CRM);
+ ha_msg_add(request, F_CRM_VERSION, CRM_VERSION);
+ ha_msg_add(request, F_CRM_MSG_TYPE, XML_ATTR_REQUEST);
+ ha_msg_add(request, XML_ATTR_REFERENCE, reference);
+ ha_msg_add(request, F_CRM_TASK, task);
+ ha_msg_add(request, F_CRM_SYS_TO, sys_to);
+ ha_msg_add(request, F_CRM_SYS_FROM, true_from);
+
+ /* HOSTTO will be ignored if it is to the DC anyway. */
+ if(host_to != NULL && strlen(host_to) > 0) {
+ ha_msg_add(request, F_CRM_HOST_TO, host_to);
+ }
+
+ if (msg_data != NULL) {
+ add_message_xml(request, F_CRM_DATA, msg_data);
+ }
+ crm_free(reference);
+ crm_free(true_from);
+
+ return request;
+}
+
+/*
+ * This method adds a copy of xml_response_data
+ */
+HA_Message *
+create_reply_adv(HA_Message *original_request,
+ crm_data_t *xml_response_data, const char *origin)
+{
+ HA_Message *reply = NULL;
+
+ const char *host_from= cl_get_string(original_request, F_CRM_HOST_FROM);
+ const char *sys_from = cl_get_string(original_request, F_CRM_SYS_FROM);
+ const char *sys_to = cl_get_string(original_request, F_CRM_SYS_TO);
+ const char *type = cl_get_string(original_request, F_CRM_MSG_TYPE);
+ const char *operation= cl_get_string(original_request, F_CRM_TASK);
+ const char *crm_msg_reference = cl_get_string(
+ original_request, XML_ATTR_REFERENCE);
+
+ if (type == NULL) {
+ crm_err("Cannot create new_message,"
+ " no message type in original message");
+ return NULL;
+#if 0
+ } else if (strcmp(XML_ATTR_REQUEST, type) != 0) {
+ crm_err("Cannot create new_message,"
+ " original message was not a request");
+ return NULL;
+#endif
+ }
+ reply = ha_msg_new(10);
+
+ ha_msg_add(reply, F_CRM_ORIGIN, origin);
+ ha_msg_add(reply, F_TYPE, T_CRM);
+ ha_msg_add(reply, F_CRM_VERSION, CRM_VERSION);
+ ha_msg_add(reply, F_CRM_MSG_TYPE, XML_ATTR_RESPONSE);
+ ha_msg_add(reply, XML_ATTR_REFERENCE, crm_msg_reference);
+ ha_msg_add(reply, F_CRM_TASK, operation);
+
+ /* since this is a reply, we reverse the from and to */
+ ha_msg_add(reply, F_CRM_SYS_TO, sys_from);
+ ha_msg_add(reply, F_CRM_SYS_FROM, sys_to);
+
+ /* HOSTTO will be ignored if it is to the DC anyway. */
+ if(host_from != NULL && strlen(host_from) > 0) {
+ ha_msg_add(reply, F_CRM_HOST_TO, host_from);
+ }
+
+ if (xml_response_data != NULL) {
+ add_message_xml(reply, F_CRM_DATA, xml_response_data);
+ }
+
+ return reply;
+}
+
+
+/*
+ * This method adds a copy of xml_response_data
+ */
+gboolean
+send_ipc_reply(IPC_Channel *ipc_channel,
+ HA_Message *request, crm_data_t *xml_response_data)
+{
+ gboolean was_sent = FALSE;
+ HA_Message *reply = NULL;
+
+ reply = create_reply(request, xml_response_data);
+
+ if (reply != NULL) {
+ was_sent = send_ipc_message(ipc_channel, reply);
+ }
+ return was_sent;
+}
+
+ha_msg_input_t *
+new_ha_msg_input(const HA_Message *orig)
+{
+ ha_msg_input_t *input_copy = NULL;
+ crm_malloc(input_copy, sizeof(ha_msg_input_t));
+
+ input_copy->msg = ha_msg_copy(orig);
+ input_copy->xml = get_message_xml(input_copy->msg, F_CRM_DATA);
+ return input_copy;
+}
+
+ha_msg_input_t *
+new_ipc_msg_input(IPC_Message *orig)
+{
+ ha_msg_input_t *input_copy = NULL;
+
+ crm_malloc(input_copy, sizeof(ha_msg_input_t));
+ input_copy->msg = ipcmsg2hamsg(orig);
+ input_copy->xml = get_message_xml(input_copy->msg, F_CRM_DATA);
+ return input_copy;
+}
+
+void
+delete_ha_msg_input(ha_msg_input_t *orig)
+{
+ if(orig == NULL) {
+ return;
+ }
+ crm_msg_del(orig->msg);
+ free_xml(orig->xml);
+ crm_free(orig);
+}
diff --git a/lib/crm/common/utils.c b/lib/crm/common/utils.c
new file mode 100644
index 0000000000..6703a69ae0
--- /dev/null
+++ b/lib/crm/common/utils.c
@@ -0,0 +1,879 @@
+/* $Id: utils.c,v 1.1 2005/04/12 12:49:02 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 _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/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);
+int crm_logfacility_from_name(const char * value);
+
+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_malloc(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_trace("Attempting to decode: [%s]", srcstring);
+ if (srcstring != NULL) {
+ len = strlen(srcstring);
+ while(lpc <= len) {
+ if (srcstring[lpc] == separator
+ || srcstring[lpc] == '\0') {
+ crm_malloc(*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_malloc(*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 *
+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_malloc(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_devel("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;
+
+ 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_malloc(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 */
+
+ 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_malloc(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();
+
+ cl_log_set_logd_channel_source(NULL, NULL);
+ 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 *function,
+ const char *alt_debugfile, 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;
+ char *buf = NULL;
+ int nbytes;
+
+ va_start(ap, fmt);
+ nbytes=vasprintf(&buf, fmt, ap);
+ va_end(ap);
+
+ log_level -= LOG_INFO;
+ if(log_level > 1) {
+ if(function == NULL) {
+ cl_log(log_as, "[%d] %s", log_level, buf);
+
+ } else {
+ cl_log(log_as, "fn(%s [%d]): %s",
+ function, log_level, buf);
+ }
+
+ } else {
+ if(function == NULL) {
+ cl_log(log_as, "%s", buf);
+
+ } else {
+ cl_log(log_as, "fn(%s): %s", function, buf);
+ }
+ }
+
+ if(nbytes > MAXLINE) {
+ cl_log(LOG_WARNING, "Log from %s() was truncated",
+ crm_str(function));
+ }
+ free(buf);
+ }
+}
+
+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_trace("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_verbose("%s < %s", version1, version2);
+ return -1;
+
+ } else if(cmp > 0) {
+ crm_verbose("%s > %s", version1, version2);
+ return 1;
+ }
+ }
+ crm_verbose("%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)
+{
+#if 1
+ 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) {
+ set_xml_property_copy(node, attr, uuid_calc);
+ return;
+ }
+
+ crm_malloc(uuid_calc, sizeof(char)*50);
+
+ if(uuid_calc != NULL) {
+ 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 {
+ uuid_unparse(uuid_raw, uuid_calc);
+ g_hash_table_insert(
+ crm_uuid_cache,
+ crm_strdup(uname), crm_strdup(uuid_calc));
+ }
+ set_xml_property_copy(node, attr, uuid_calc);
+ }
+
+ crm_free(uuid_calc);
+#else
+ set_xml_property_copy(node, attr, uname);
+#endif
+}/*memory leak*/ /* BEAM BUG - this is not a memory leak */
+
+extern int use_logging_daemon;
+extern int conn_logd_intval;
+
+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_verbose("Facility: %d", facility);
+
+ param_name = KEY_LOGFILE;
+ param_val = hb_cluster->llc_ops->get_parameter(hb_cluster, param_name);
+ crm_devel("%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_devel("%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_devel("%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_devel("%s = %s", param_name, param_val);
+ if(param_val != NULL) {
+ crm_str_to_boolean(param_val, &use_logging_daemon);
+ if(use_logging_daemon) {
+ 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_devel("%s = %s", param_name, param_val);
+ if(param_val != NULL) {
+ conn_logd_intval = crm_get_msec(param_val);
+ 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 = crm_logfacility_from_name(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) {
+ crm_str_to_boolean(param_val, &use_logging_daemon);
+ if(use_logging_daemon) {
+ cl_set_logging_wqueue_maxlen(500);
+ }
+ 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) {
+ conn_logd_intval = crm_get_msec(param_val);
+ param_val = NULL;
+ }
+
+}
+
+struct _syslog_code {
+ const char *c_name;
+ int c_val;
+};
+
+
+struct _syslog_code facilitynames[] =
+{
+#ifdef LOG_AUTH
+ { "auth", LOG_AUTH },
+ { "security", LOG_AUTH }, /* DEPRECATED */
+#endif
+#ifdef LOG_AUTHPRIV
+ { "authpriv", LOG_AUTHPRIV },
+#endif
+#ifdef LOG_CRON
+ { "cron", LOG_CRON },
+#endif
+#ifdef LOG_DAEMON
+ { "daemon", LOG_DAEMON },
+#endif
+#ifdef LOG_FTP
+ { "ftp", LOG_FTP },
+#endif
+#ifdef LOG_KERN
+ { "kern", LOG_KERN },
+#endif
+#ifdef LOG_LPR
+ { "lpr", LOG_LPR },
+#endif
+#ifdef LOG_MAIL
+ { "mail", LOG_MAIL },
+#endif
+
+/* { "mark", INTERNAL_MARK }, * INTERNAL */
+
+#ifdef LOG_NEWS
+ { "news", LOG_NEWS },
+#endif
+#ifdef LOG_SYSLOG
+ { "syslog", LOG_SYSLOG },
+#endif
+#ifdef LOG_USER
+ { "user", LOG_USER },
+#endif
+#ifdef LOG_UUCP
+ { "uucp", LOG_UUCP },
+#endif
+#ifdef LOG_LOCAL0
+ { "local0", LOG_LOCAL0 },
+#endif
+#ifdef LOG_LOCAL1
+ { "local1", LOG_LOCAL1 },
+#endif
+#ifdef LOG_LOCAL2
+ { "local2", LOG_LOCAL2 },
+#endif
+#ifdef LOG_LOCAL3
+ { "local3", LOG_LOCAL3 },
+#endif
+#ifdef LOG_LOCAL4
+ { "local4", LOG_LOCAL4 },
+#endif
+#ifdef LOG_LOCAL5
+ { "local5", LOG_LOCAL5 },
+#endif
+#ifdef LOG_LOCAL6
+ { "local6", LOG_LOCAL6 },
+#endif
+#ifdef LOG_LOCAL7
+ { "local7", LOG_LOCAL7 },
+#endif
+ { NULL, -1 }
+};
+
+/* set syslog facility config variable */
+int
+crm_logfacility_from_name(const char * value)
+{
+ int lpc;
+ for(lpc = 0; facilitynames[lpc].c_name != NULL; lpc++) {
+ if(strcmp(value, facilitynames[lpc].c_name) == 0) {
+ return facilitynames[lpc].c_val;
+ }
+ }
+ return -1;
+}
+
+gboolean
+crm_is_true(const char * s)
+{
+ gboolean ret = FALSE;
+ crm_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 (*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);
+}
diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c
new file mode 100644
index 0000000000..98716273f4
--- /dev/null
+++ b/lib/crm/common/xml.c
@@ -0,0 +1,1654 @@
+/* $Id: xml.c,v 1.1 2005/04/12 12:49:07 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 <sys/param.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <clplumbing/ipc.h>
+#include <clplumbing/cl_log.h>
+
+#include <crm/crm.h>
+#include <crm/msg_xml.h>
+#include <crm/common/xml.h>
+#include <crm/dmalloc_wrapper.h>
+
+
+void dump_array(
+ int log_level, const char *message, const char **array, int depth);
+
+int print_spaces(char *buffer, int spaces);
+
+int log_data_element(
+ const char *function, int log_level, int depth, crm_data_t *data, gboolean formatted);
+
+int dump_data_element(
+ int depth, char **buffer, crm_data_t *data, gboolean formatted);
+
+#ifndef USE_LIBXML
+
+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);
+
+#endif
+
+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_insane("returning node (%s).", xmlGetNodePath(a_child)); */
+ crm_xml_insane(a_child, "contents\t%s");
+ crm_xml_insane(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_devel("Could not find %s in %s.", search_path, xmlGetNodePath(root));
+ } else {
+ crm_devel("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_INSANE, "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_insane("returning node (%s).",
+ xmlGetNodePath(lastMatch));
+
+ crm_xml_insane(lastMatch, "found\t%s");
+ crm_xml_insane(root, "in \t%s");
+
+ crm_validate_data(lastMatch);
+ return lastMatch;
+ }
+
+ dump_array(LOG_WARNING,
+ "Could not find the full path to the node you specified.",
+ search_path, len);
+
+ crm_warn("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_devel("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,
+ gboolean siblings)
+{
+ 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_devel("returning node (%s).",
+ xmlGetNodePath(a_child));
+ return a_child;
+ }
+ );
+ if(siblings) {
+ abort();
+ }
+
+
+ crm_debug("node <%s id=%s> not found in %s.",
+ node_name, id, xmlGetNodePath(parent));
+ return NULL;
+}
+
+void
+copy_in_properties(crm_data_t* target, 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,
+ set_xml_property_copy(
+ target, local_prop_name, local_prop_value);
+ );
+ crm_validate_data(target);
+ }
+
+ return;
+}
+
+crm_data_t*
+add_node_copy(crm_data_t *new_parent, 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) {
+#ifdef USE_LIBXML
+ node_copy = copy_xml_node_recursive(xml_node);
+ xmlAddChild(new_parent, node_copy);
+#else
+ 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), FALSE);
+ crm_validate_data(node_copy);
+ crm_update_parents(new_parent);
+ crm_validate_data(new_parent);
+#endif
+
+ } 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 *
+set_xml_property_copy(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_insane("[%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 {
+#ifdef USE_LIBXML
+ const char *local_name = NULL;
+ const char *local_value = NULL;
+ local_value = crm_strdup(value);
+ local_name = crm_strdup(name);
+ xmlUnsetProp(node, local_name);
+ xmlSetProp(node, local_name, local_value);
+ return xmlGetProp(node, local_name);
+#else
+ crm_validate_data(node);
+ ha_msg_mod(node, name, value);
+ return crm_element_value(node, name);
+#endif
+ }
+
+ 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 {
+#ifdef USE_LIBXML
+ local_name = crm_strdup(name);
+
+ if(parent == NULL)
+ ret_value = xmlNewNode(NULL, local_name);
+ else {
+ parent_name = parent->name;
+ ret_value =
+ xmlNewChild(parent, NULL, local_name, NULL);
+ }
+#else
+ local_name = name;
+ ret_value = ha_msg_new(1);
+ CRM_DEV_ASSERT(ret_value != NULL);
+
+ set_xml_property_copy(ret_value, F_XML_TAGNAME, name);
+ crm_validate_data(ret_value);
+ if(parent) {
+ crm_validate_data(parent);
+ parent_name = crm_element_name(parent);
+ crm_insane("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);
+ }
+#endif
+ }
+
+ crm_insane("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);
+#ifdef USE_LIBXML
+ xmlUnlinkNode(a_node);
+ node->doc = NULL;
+ free_xml_fn(a_node);
+#else
+ cl_msg_remove_value(parent, a_node);
+#endif
+ crm_validate_data(parent);
+}
+
+
+void
+free_xml_fn(crm_data_t *a_node)
+{
+ if(a_node == NULL) {
+ ; /* nothing to do */
+#ifdef USE_LIBXML
+ } else if (a_node->doc != NULL) {
+ xmlFreeDoc(a_node->doc);
+ } else {
+ /* make sure the node is unlinked first */
+ xmlUnlinkNode(a_node);
+ xmlFreeNode(a_node);
+#else
+ } 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);
+ }
+#endif
+ }
+
+ return;
+}
+
+void
+set_node_tstamp(crm_data_t *a_node)
+{
+ 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_malloc(since_epoch, 128*(sizeof(char)));
+ if(since_epoch != NULL) {
+ sprintf(since_epoch, "%ld", (unsigned long)a_time);
+#ifdef USE_LIBXML
+ xmlUnsetProp(a_node, XML_ATTR_TSTAMP);
+ xmlSetProp(a_node, XML_ATTR_TSTAMP, since_epoch);
+#else
+ 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_node_recursive(crm_data_t *src_node)
+{
+ crm_data_t *new_xml = NULL;
+
+#ifdef USE_LIBXML
+# if 1
+ return xmlCopyNode(src_node, 1);
+# else
+ xmlNodePtr local_node = NULL, local_child = NULL;
+
+ if(src_node == NULL || src_node->name == NULL) {
+ return NULL;
+ }
+
+ local_node = create_xml_node(NULL, src_node->name);
+
+ copy_in_properties(local_node, src_node);
+
+ xml_child_iter(
+ src_node, node_iter, NULL,
+ local_child = copy_xml_node_recursive(node_iter);
+ if(local_child != NULL) {
+ xmlAddChild(local_node, local_child);
+ crm_insane("Copied node [%s [%s]",
+ local_node->name, local_child->name);
+ }
+ );
+
+ crm_insane("Returning [%s]", local_node->name);
+ return local_node;
+# endif
+#else
+ 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_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);
+#endif
+ return new_xml;
+}
+
+
+crm_data_t*
+string2xml(const char *input)
+{
+#ifdef USE_LIBXML
+ int lpc = 0;
+ char ch = 0;
+ int input_len = 0;
+ gboolean more = TRUE;
+ gboolean inTag = FALSE;
+ crm_data_t *xml_object = NULL;
+ const char *the_xml;
+ xmlDocPtr doc;
+ xmlBufferPtr xml_buffer = NULL;
+
+ if(input == NULL || (input_len = strlen(input)) < 0) {
+ return NULL;
+ }
+
+ xml_buffer = xmlBufferCreate();
+
+ for(lpc = 0; (lpc < input_len) && more; lpc++) {
+ ch = input[lpc];
+ switch(ch) {
+ case EOF:
+ case 0:
+ ch = 0;
+ more = FALSE;
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ break;
+ case '>':
+ case '<':
+ inTag = TRUE;
+ if(ch == '>') inTag = FALSE;
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ break;
+ case '\n':
+ case '\t':
+ case ' ':
+ ch = ' ';
+ if(inTag) {
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ }
+ break;
+ default:
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ break;
+ }
+ }
+
+
+ xmlInitParser();
+ the_xml = xmlBufferContent(xml_buffer);
+ doc = xmlParseMemory(the_xml, strlen(the_xml));
+ xmlCleanupParser();
+
+ if (doc == NULL) {
+ crm_err("Malformed XML [xml=%s]", the_xml);
+ xmlBufferFree(xml_buffer);
+ return NULL;
+ }
+
+ xmlBufferFree(xml_buffer);
+ xml_object = xmlDocGetRootElement(doc);
+
+ return xml_object;
+#else
+ crm_data_t *output = parse_xml(input, NULL);
+ if(output != NULL) {
+ crm_update_parents(output);
+ crm_validate_data(output);
+ }
+ return output;
+#endif
+}
+
+crm_data_t *
+stdin2xml(void)
+{
+#ifdef USE_LIBXML
+ return file2xml(stdin);
+#else
+ int lpc = 0;
+ int MAX_XML_BUFFER = 20000;
+
+ char ch = 0;
+ gboolean more = TRUE;
+ gboolean inTag = FALSE;
+ FILE *input = stdin;
+
+ char *xml_buffer = NULL;
+ crm_data_t *xml_obj = NULL;
+
+ crm_malloc(xml_buffer, sizeof(char)*(MAX_XML_BUFFER+1));
+
+ while (more && lpc < MAX_XML_BUFFER) {
+ ch = fgetc(input);
+/* crm_devel("Got [%c]", ch); */
+ switch(ch) {
+ case EOF:
+ case 0:
+ ch = 0;
+ more = FALSE;
+ xml_buffer[lpc++] = ch;
+ break;
+ case '>':
+ case '<':
+ inTag = TRUE;
+ if(ch == '>') { inTag = FALSE; }
+ xml_buffer[lpc++] = ch;
+ break;
+ case '\n':
+ case '\t':
+ case ' ':
+ ch = ' ';
+ if(inTag) {
+ xml_buffer[lpc++] = ch;
+ }
+ break;
+ default:
+ xml_buffer[lpc++] = ch;
+ break;
+ }
+ }
+
+ xml_buffer[MAX_XML_BUFFER] = 0;
+ xml_obj = string2xml(xml_buffer);
+ crm_free(xml_buffer);
+
+ crm_xml_devel(xml_obj, "Created fragment");
+ return xml_obj;
+#endif
+}
+
+
+crm_data_t*
+file2xml(FILE *input)
+{
+
+#ifdef USE_LIBXML
+ char ch = 0;
+ gboolean more = TRUE;
+ gboolean inTag = FALSE;
+ crm_data_t *xml_object = NULL;
+ xmlBufferPtr xml_buffer = xmlBufferCreate();
+ const char *the_xml;
+ xmlDocPtr doc;
+
+ if(input == NULL) {
+ crm_err("File pointer was NULL");
+ return NULL;
+ }
+
+ while (more) {
+ ch = fgetc(input);
+/* crm_devel("Got [%c]", ch); */
+ switch(ch) {
+ case EOF:
+ case 0:
+ ch = 0;
+ more = FALSE;
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ break;
+ case '>':
+ case '<':
+ inTag = TRUE;
+ if(ch == '>') inTag = FALSE;
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ break;
+ case '\n':
+ case '\t':
+ case ' ':
+ ch = ' ';
+ if(inTag) {
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ }
+ break;
+ default:
+ xmlBufferAdd(xml_buffer, &ch, 1);
+ break;
+ }
+ }
+
+ xmlInitParser();
+ the_xml = xmlBufferContent(xml_buffer);
+ doc = xmlParseMemory(the_xml, strlen(the_xml));
+ xmlCleanupParser();
+
+ if (doc == NULL) {
+ crm_err("Malformed XML [xml=%s]", the_xml);
+ xmlBufferFree(xml_buffer);
+ return NULL;
+ }
+ xmlBufferFree(xml_buffer);
+ xml_object = xmlDocGetRootElement(doc);
+
+ crm_xml_devel(xml_object, "Created fragment");
+
+ return xml_object;
+#else
+ 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_devel("Reading %d bytes from file", length);
+ crm_malloc(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;
+#endif
+}
+
+void
+dump_array(int log_level, const char *message, const char **array, int depth)
+{
+ int j;
+
+ if(message != NULL) {
+ do_crm_log(log_level, __FUNCTION__, NULL, "%s", message);
+ }
+
+ do_crm_log(log_level, __FUNCTION__, NULL, "Contents of the array:");
+ if(array == NULL || array[0] == NULL || depth == 0) {
+ do_crm_log(log_level, __FUNCTION__, NULL, "\t<empty>");
+ return;
+ }
+
+ for (j=0; j < depth && array[j] != NULL; j++) {
+ if (array[j] == NULL) { break; }
+ do_crm_log(log_level, __FUNCTION__, NULL, "\t--> (%s).", array[j]);
+ }
+}
+
+int
+write_xml_file(crm_data_t *xml_node, const char *filename)
+{
+ int res = 0;
+ char now_str[30];
+ time_t now;
+
+ crm_devel("Writing XML out to %s", filename);
+ crm_validate_data(xml_node);
+ if (xml_node == NULL) {
+ return -1;
+ }
+
+ crm_validate_data(xml_node);
+ crm_xml_trace(xml_node, "Writing out");
+ crm_validate_data(xml_node);
+
+ now = time(NULL);
+ ctime_r(&now, now_str);
+ now_str[24] = EOS; /* replace the newline */
+ set_xml_property_copy(xml_node, "last_written", now_str);
+ crm_validate_data(xml_node);
+
+#ifdef USE_LIBXML
+ if (xml_node->doc == NULL) {
+ xmlDocPtr foo = NULL;
+ crm_insane("Creating doc pointer for %s", xml_node->name);
+ foo = xmlNewDoc("1.0");
+ xmlDocSetRootElement(foo, xml_node);
+ xmlSetTreeDoc(xml_node, foo);
+ }
+
+ /* save it.
+ * set arg 3 to 0 to disable line breaks,1 to enable
+ * res == num bytes saved
+ */
+ res = xmlSaveFormatFile(filename, xml_node->doc, 1);
+ /* for some reason, reading back after saving with
+ * line-breaks doesnt go real well
+ */
+#else
+ {
+ FILE *file_output_strm = fopen(filename, "w");
+ char *buffer = dump_xml_formatted(xml_node);
+ CRM_DEV_ASSERT(buffer != NULL && strlen(buffer) > 0);
+ if(file_output_strm == NULL) {
+ res = -1;
+ crm_err("Cannot write to %s", filename);
+
+ } else if(buffer != NULL && strlen(buffer) > 0) {
+ res = fprintf(file_output_strm, "%s", buffer);
+ }
+ if(file_output_strm != NULL) {
+ fflush(file_output_strm);
+ fclose(file_output_strm);
+ }
+
+ crm_free(buffer);
+ }
+#endif
+ crm_devel("Saved %d bytes to the Cib as XML", res);
+
+ return res;
+}
+
+void
+print_xml_formatted(int log_level, const char *function,
+ crm_data_t *msg, const char *text)
+{
+ if(msg == NULL) {
+ do_crm_log(log_level, function, NULL, "%s: %s",
+ crm_str(text), "<null>");
+ return;
+ }
+
+ crm_validate_data(msg);
+ do_crm_log(log_level, function, NULL, "%s:",
+ crm_str(text));
+ log_data_element(function, 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;
+#ifdef USE_LIBXML
+ const char *xml_text = cl_get_string(msg, field);
+ xml_node = string2xml(xml_text);
+#else
+ 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_node_recursive(tmp_node);
+ }
+#endif
+ return xml_node;
+}
+
+gboolean
+add_message_xml(HA_Message *msg, const char *field, crm_data_t *xml)
+{
+ crm_validate_data(xml);
+#ifdef USE_LIBXML
+ char *buffer = dump_xml_unformatted(xml);
+ CRM_DEV_ASSERT(buffer != NULL);
+ if(buffer != NULL) {
+ CRM_DEV_ASSERT(cl_is_allocated(buffer));
+ ha_msg_add(msg, field, buffer);
+ crm_devel("Added XML to message");
+ CRM_DEV_ASSERT(cl_is_allocated(buffer));
+ crm_free(buffer);
+ }
+#else
+ crm_validate_data(msg);
+ ha_msg_addstruct(msg, field, xml);
+ crm_update_parents(msg);
+#endif
+ return TRUE;
+}
+
+
+char *
+dump_xml_formatted(crm_data_t *an_xml_node)
+{
+ char *buffer = NULL;
+#if 0
+ int len = 0;
+ xmlChar *xml_buffer = NULL;
+ xmlDocPtr foo = NULL;
+
+ crm_data_t* xml_node = NULL;
+
+ xml_node = copy_xml_node_recursive(an_xml_node);
+
+ if (xml_node == NULL) {
+ return NULL;
+
+ } else {
+ /* reset the doc pointer */
+ crm_insane("Creating doc pointer for %s", xml_node->name);
+ foo = xmlNewDoc("1.0");
+ xmlDocSetRootElement(foo, xml_node);
+ xmlSetTreeDoc(xml_node, foo);
+ crm_insane("Doc pointer set for %s", xml_node->name);
+ }
+
+ crm_insane("Initializing Parser");
+ xmlInitParser();
+ crm_insane("Dumping data");
+ xmlDocDumpFormatMemory(xml_node->doc, &xml_buffer, &len, 1);
+ crm_insane("Cleaning up parser");
+ xmlCleanupParser();
+
+ crm_insane("Copying memory into crm_ space");
+ if(xml_buffer != NULL && len > 0) {
+ /* copy the text into crm_ memory */
+ buffer = crm_strdup(xml_buffer);
+ xmlFree(xml_buffer);
+ }
+ crm_insane("Buffer coppied");
+
+ free_xml(xml_node);
+#else
+ char *mutable_ptr = NULL;
+/* crm_malloc(buffer, 2*(an_xml_node->stringlen)); */
+ crm_malloc(buffer, sizeof(char)*30000);
+ 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_trace("Dumped: %s", buffer);
+#endif
+ return buffer;
+}
+
+char *
+dump_xml_unformatted(crm_data_t *an_xml_node)
+{
+ char *buffer = NULL;
+#if 0
+ int lpc = 0;
+ int len = 0;
+ xmlChar *xml_buffer = NULL;
+ xmlDocPtr foo = NULL;
+
+ crm_data_t* xml_node = NULL;
+
+ xml_node = copy_xml_node_recursive(an_xml_node);
+
+ if (xml_node == NULL) {
+ return NULL;
+
+ } else {
+ /* reset the doc pointer */
+ crm_insane("Creating doc pointer for %s", xml_node->name);
+ foo = xmlNewDoc("1.0");
+ xmlDocSetRootElement(foo, xml_node);
+ xmlSetTreeDoc(xml_node, foo);
+ crm_insane("Doc pointer set for %s", xml_node->name);
+ }
+
+ crm_insane("Initializing Parser");
+ xmlInitParser();
+ crm_insane("Dumping data");
+ xmlDocDumpFormatMemory(xml_node->doc, &xml_buffer, &len, 0);
+ crm_insane("Cleaning up parser");
+ xmlCleanupParser();
+
+ crm_insane("Copying memory into crm_ space");
+ if(xml_buffer != NULL && len > 0) {
+ /* copy the text into crm_ memory */
+ buffer = crm_strdup(xml_buffer);
+ xmlFree(xml_buffer);
+ }
+ crm_insane("Buffer coppied");
+
+ free_xml(xml_node);
+
+ /* remove <?xml version="1.0"?> and the newline */
+/* for(lpc = 0; lpc < len; lpc++) { */
+/* if(buffer[lpc] == '\n') { */
+/* buffer[lpc] = ' '; */
+/* break; */
+/* } else { */
+/* buffer[lpc] = ' '; */
+/* } */
+/* } */
+/* for(lpc = len - 2; lpc > 0 && lpc < len; lpc++) { */
+ for(lpc = 0; lpc < len; lpc++) {
+ if(buffer[lpc] == '\n') {
+ crm_devel("Reset newline at %d", lpc);
+ buffer[lpc] = ' ';
+ }
+ }
+ crm_devel("Processed %d chars for newlines", lpc);
+#else
+ char *mutable_ptr = NULL;
+/* crm_malloc(buffer, 2*(an_xml_node->stringlen)); */
+ crm_malloc(buffer, sizeof(char)*20000);
+ 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_trace("Dumped: %s", buffer);
+#endif
+ 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, int log_level, int depth,
+ 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_insane("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, 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_insane("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", print_buffer);
+ buffer = print_buffer;
+
+ if(has_children == 0) {
+ return 0;
+ }
+
+ xml_child_iter(
+ data, a_child, NULL,
+ child_result = log_data_element(
+ function, 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>",
+ print_buffer, name);
+ crm_insane("Dumped %s...", name);
+
+ return has_children;
+}
+
+
+int
+dump_data_element(
+ int depth, char **buffer, 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_insane("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_insane("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_insane("Dumped %s...", name);
+
+ return has_children;
+}
+
+gboolean
+xml_has_children(crm_data_t *xml_root)
+{
+ crm_validate_data(xml_root);
+
+#ifdef USE_LIBXML
+ if(xml_root != NULL && xml_root->children != NULL) {
+ return TRUE;
+ }
+#else
+ xml_child_iter(
+ xml_root, a_child, NULL,
+ return TRUE;
+ );
+#endif
+ return FALSE;
+}
+
+
+void
+crm_validate_data(const crm_data_t *xml_root)
+{
+#ifdef USE_LIBXML
+ CRM_DEV_ASSERT(xml_root != NULL);
+#else
+# ifndef XML_PARANOIA_CHECKS
+ CRM_DEV_ASSERT(xml_root != NULL);
+# else
+ int lpc = 0;
+ CRM_ASSERT(xml_root != NULL);
+ CRM_ASSERT(cl_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(cl_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(cl_is_allocated(child) == 1);
+/* } else { */
+/* CRM_DEV_ASSERT(FALSE); */
+ }
+ }
+# endif
+#endif
+}
+
+
+/* FIXME!! This whole function is evil!! */
+void
+crm_set_element_parent(crm_data_t *data, crm_data_t *parent)
+{
+#ifdef USE_LIBXML
+ CRM_DEV_ASSERT(FALSE/* not implemented*/);
+#else
+ 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);
+ }
+#endif
+}
+
+const char *
+crm_element_value(crm_data_t *data, const char *name)
+{
+#ifdef USE_LIBXML
+ return xmlGetProp(data, name);
+#else
+ const char *value = NULL;
+ crm_validate_data(data);
+ value = cl_get_string(data, name);
+ if(value != NULL) {
+ cl_is_allocated(value);
+ }
+ return value;
+#endif
+}
+
+char *
+crm_element_value_copy(crm_data_t *data, const char *name)
+{
+ const char *value = NULL;
+ char *value_copy = NULL;
+#ifdef USE_LIBXML
+ value = xmlGetProp(data, name);
+#else
+ crm_validate_data(data);
+ value = cl_get_string(data, name);
+ if(value != NULL) {
+ cl_is_allocated(value);
+ }
+#endif
+ CRM_DEV_ASSERT(value != NULL);
+ if(value != NULL) {
+ value_copy = crm_strdup(value);
+ }
+ return value_copy;
+}
+
+const char *
+crm_element_name(crm_data_t *data)
+{
+#ifdef USE_LIBXML
+ return (data ? data->name : NULL);
+#else
+ crm_validate_data(data);
+ return cl_get_string(data, F_XML_TAGNAME);
+#endif
+}
+
+void
+xml_remove_prop(crm_data_t *obj, const char *name)
+{
+#ifdef USE_LIBXML
+ xmlUnsetProp(obj, name);
+#else
+ if(crm_element_value(obj, name) != NULL) {
+ cl_msg_remove(obj, name);
+ }
+#endif
+}
+
+void
+crm_update_parents(crm_data_t *xml_root)
+{
+#ifndef USE_LIBXML
+ 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);
+ );
+#endif
+}
+
+
+#ifndef USE_LIBXML
+
+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_insane("Processing char %c [%d]", ch, lpc);
+
+ switch(ch) {
+ case EOF:
+ 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 {
+ 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_insane("Processing char %c[%d]", ch, lpc);
+
+ switch(ch) {
+ case EOF:
+ 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 {
+ 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_insane("Processing char %c [%d]", ch, lpc);
+
+ switch(ch) {
+ case EOF:
+ case 0:
+ error = "unexpected EOS";
+ break;
+ case '\\':
+ if(input[lpc+1] == '"') {
+ /* skip over the next char */
+ lpc++;
+ break;
+ }
+ /*fall through*/
+ case '"':
+ return lpc;
+ default:
+ break;
+ }
+ }
+ crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
+ return -1;
+}
+
+
+crm_data_t*
+parse_xml(const char *input, int *offset)
+{
+ int len = 0, lpc = 0;
+ char ch = 0;
+ char *tag_name = NULL;
+ char *attr_name = NULL;
+ char *attr_value = NULL;
+ gboolean more = TRUE;
+ const char *error = NULL;
+ const char *our_input = input;
+ crm_data_t *new_obj = NULL;
+
+ if(offset != NULL) {
+ our_input = input + (*offset);
+ }
+
+ len = strlen(our_input);
+ while(lpc < len) {
+ if(our_input[lpc] != '<') {
+
+ } else if(our_input[lpc+1] == '!') {
+ crm_err("XML Comments are not supported");
+ crm_insane("Skipping char %c", our_input[lpc]);
+ lpc++;
+
+ } else if(our_input[lpc+1] == '?') {
+ crm_insane("Skipping char %c", our_input[lpc]);
+ lpc++;
+ } else {
+ lpc++;
+ our_input += lpc;
+ break;
+ }
+ crm_insane("Skipping char %c", our_input[lpc]);
+ lpc++;
+ }
+
+ len = get_tag_name(our_input);
+ if(len < 0) {
+ return NULL;
+ }
+ crm_malloc(tag_name, len+1);
+ strncpy(tag_name, our_input, len+1);
+ tag_name[len] = EOS;
+ crm_devel("Processing tag %s", tag_name);
+
+ new_obj = ha_msg_new(1);
+ CRM_DEV_ASSERT(cl_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_insane("Processing char %c[%d]", ch, lpc);
+ switch(ch) {
+ case EOF:
+ case 0:
+ error = "unexpected EOS";
+ break;
+ case '/':
+ if(our_input[lpc+1] == '>') {
+ more = FALSE;
+ }
+ break;
+ case '<':
+ if(our_input[lpc+1] != '/') {
+ crm_data_t *child = NULL;
+ crm_devel("Start parsing child...");
+ child = parse_xml(our_input, &lpc);
+ if(child == NULL) {
+ error = "error parsing child";
+ } else {
+ CRM_DEV_ASSERT(cl_is_allocated(child) == 1);
+ ha_msg_addstruct(
+ new_obj, crm_element_name(child), child);
+ crm_devel("Finished parsing child: %s",
+ crm_element_name(child));
+/* lpc++; /\* > *\/ */
+ }
+
+ } else {
+ lpc += 2; /* </ */
+ len = get_tag_name(our_input+lpc);
+ if(len < 0) {
+ error = "couldnt find tag";
+ } else if(strncmp(our_input+lpc, tag_name, len) == 0) {
+ more = FALSE;
+ lpc += len;
+/* lpc++; /\* > *\/ */
+ if(our_input[lpc] != '>') {
+ error = "clase tag cannot contain attrs";
+ }
+ crm_devel("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_malloc(attr_value, len+1);
+ strncpy(attr_value, our_input+lpc, len+1);
+ attr_value[len] = EOS;
+ lpc += len;
+/* lpc++; /\* " *\/ */
+
+ crm_devel("creating nvpair: <%s %s=\"%s\"...",
+ tag_name,
+ crm_str(attr_name),
+ crm_str(attr_value));
+
+ ha_msg_add(new_obj, attr_name, attr_value);
+ crm_free(attr_name);
+ crm_free(attr_value);
+ }
+ break;
+ case '>':
+ case ' ':
+ case '\t':
+ case '\n':
+ break;
+ default:
+ len = get_attr_name(our_input+lpc);
+ if(len < 0) {
+ error = "couldnt find attr_name";
+ } else {
+ crm_malloc(attr_name, len+1);
+ strncpy(attr_name, our_input+lpc, len+1);
+ attr_name[len] = EOS;
+ lpc += len;
+ crm_trace("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_devel("Finished processing %s tag", tag_name);
+ crm_free(tag_name);
+ if(offset != NULL) {
+ (*offset) += lpc;
+ }
+
+ CRM_DEV_ASSERT(cl_is_allocated(new_obj) == 1);
+ return new_obj;
+}
+
+
+#endif
+
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 10, 1:34 AM (20 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009526
Default Alt Text
(80 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment