Page MenuHomeClusterLabs Projects

No OneTemporary

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

Mime Type
text/x-diff
Expires
Thu, Jul 10, 1:34 AM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2009526
Default Alt Text
(80 KB)

Event Timeline