Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F1841268
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
75 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/crm/admin/Makefile.am b/crm/admin/Makefile.am
index 445a8591e5..1033093d5d 100644
--- a/crm/admin/Makefile.am
+++ b/crm/admin/Makefile.am
@@ -1,105 +1,101 @@
#
# 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)
halibdir = $(libdir)/@HB_PKG@
hasbindir = $(sbindir)
LIBRT = @LIBRT@
AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS)
-
-COMMONLIBS = $(CRM_DEBUG_LIBS) \
- $(top_builddir)/lib/clplumbing/libplumb.la \
- $(top_builddir)/lib/pils/libpils.la \
- $(top_builddir)/lib/crm/common/libcrmcommon.la \
- $(top_builddir)/lib/crm/cib/libcib.la \
- $(top_builddir)/lib/apphb/libapphb.la \
- $(top_builddir)/lib/hbclient/libhbclient.la \
- $(GLIBLIB) \
- $(CURSESLIBS) \
+AM_LDFLAGS = -L$(top_builddir)/membership/ccm \
+ -L$(top_builddir)/lib/hbclient \
+ -L$(top_builddir)/lib/clplumbing \
+ -L$(top_builddir)/lib/crm/common \
+ -L$(top_builddir)/lib/crm/pengine \
+ -L$(top_builddir)/lib/crm/cib \
+ @LDFLAGS@
+
+COMMONLIBS = $(CRM_DEBUG_LIBS) \
+ -lplumb -lhbclient -lcrmcommon -lcib \
+ $(GLIBLIB) \
+ $(CURSESLIBS) \
$(LIBRT)
halib_PYTHON = crm_primitive.py crm_utils.py crm_commands.py
hasbin_PROGRAMS = crmadmin cibadmin ccm_tool crm_diff crm_mon iso8601 \
crm_master crm_standby crm_failcount crm_attribute \
crm_resource crm_verify crm_uuid
hasbin_SCRIPTS = crm_sh
## SOURCES
#noinst_HEADERS = config.h control.h crmd.h
noinst_HEADERS =
crmadmin_SOURCES = crmadmin.c
-crmadmin_LDADD = $(COMMONLIBS) \
- $(top_builddir)/lib/crm/pengine/libpe_status.la
+crmadmin_LDADD = $(COMMONLIBS) -lpe_status
crm_uuid_SOURCES = crm_uuid.c
-crm_uuid_LDADD = $(GLIBLIB) $(top_builddir)/lib/clplumbing/libplumb.la
+crm_uuid_LDADD = $(GLIBLIB) -lplumb
cibadmin_SOURCES = cibadmin.c
cibadmin_LDADD = $(COMMONLIBS)
ccm_tool_SOURCES = ccm_epoche.c
-ccm_tool_LDADD = $(COMMONLIBS) \
- $(top_builddir)/membership/ccm/libccmclient.la
+ccm_tool_LDADD = $(COMMONLIBS) -lccmclient
crm_diff_SOURCES = xml_diff.c
crm_diff_LDADD = $(COMMONLIBS)
crm_mon_SOURCES = crm_mon.c
-crm_mon_LDADD = $(COMMONLIBS) \
- $(top_builddir)/lib/crm/pengine/libpe_status.la
+crm_mon_LDADD = $(COMMONLIBS) -lpe_status
# Arguments could be made that this should live in crm/pengine
crm_verify_SOURCES = crm_verify.c
-crm_verify_LDADD = $(COMMONLIBS) \
- $(top_builddir)/lib/crm/pengine/libpe_status.la \
- $(top_builddir)/crm/pengine/libpengine.la
+crm_verify_LDADD = $(COMMONLIBS) -lpe_status -lpengine
crm_master_SOURCES = crm_attribute.c
crm_master_LDADD = $(COMMONLIBS)
crm_standby_SOURCES = crm_attribute.c
crm_standby_LDADD = $(COMMONLIBS)
crm_attribute_SOURCES = crm_attribute.c
crm_attribute_LDADD = $(COMMONLIBS)
crm_failcount_SOURCES = crm_attribute.c
crm_failcount_LDADD = $(COMMONLIBS)
crm_resource_SOURCES = crm_resource.c
-crm_resource_LDADD = $(COMMONLIBS) \
- $(top_builddir)/lib/crm/pengine/libpe_status.la
+crm_resource_LDADD = $(COMMONLIBS) -lpe_status
iso8601_SOURCES = test.iso8601.c
iso8601_LDADD = $(COMMONLIBS)
clean-generic:
rm -f *.log *.debug *.xml *~
install-exec-local:
uninstall-local:
diff --git a/crm/cib/Makefile.am b/crm/cib/Makefile.am
index c4113833ac..b0b7a1452d 100644
--- a/crm/cib/Makefile.am
+++ b/crm/cib/Makefile.am
@@ -1,74 +1,77 @@
#
# 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)
EXTRA_DIST = cib.pam
hadir = $(sysconfdir)/ha.d
halibdir = $(libdir)/@HB_PKG@
commmoddir = $(halibdir)/modules/comm
havarlibdir = $(localstatedir)/lib/@HB_PKG@
# sockets with path
crmdir = $(havarlibdir)/crm
apigid = @HA_APIGID@
crmuid = @HA_CCMUID@
crmreqsocket = $(havarlibdir)/api/crm.req
crmressocket = $(havarlibdir)/api/crm.rsp
-COMMONLIBS = $(CRM_DEBUG_LIBS) \
- $(top_builddir)/lib/clplumbing/libplumb.la \
- $(top_builddir)/lib/crm/common/libcrmcommon.la \
- $(top_builddir)/lib/hbclient/libhbclient.la \
- $(top_builddir)/lib/crm/cib/libcib.la \
- $(GLIBLIB) \
+COMMONLIBS = $(CRM_DEBUG_LIBS) \
+ -lccmclient -lhbclient -lplumb \
+ -lcrmcommon -lpe_rules -lcib \
+ $(GLIBLIB) \
$(LIBRT)
LIBRT = @LIBRT@
AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS)
+AM_LDFLAGS = -L$(top_builddir)/membership/ccm \
+ -L$(top_builddir)/lib/hbclient \
+ -L$(top_builddir)/lib/clplumbing \
+ -L$(top_builddir)/lib/crm/common \
+ -L$(top_builddir)/lib/crm/cib \
+ @LDFLAGS@
## binary progs
halib_PROGRAMS = cib cibmon
## SOURCES
#noinst_HEADERS = config.h control.h crmd.h
noinst_HEADERS = cibio.h cibmessages.h cibprimatives.h notify.h \
callbacks.h
cib_SOURCES = io.c primatives.c messages.c cib.c notify.c \
callbacks.c main.c remote.c
-cib_LDADD = $(COMMONLIBS) $(CRYPTOLIB) \
- $(top_builddir)/membership/ccm/libccmclient.la
+cib_LDADD = $(COMMONLIBS) $(CRYPTOLIB)
cib_LDFLAGS = $(GNUTLSLIBS)
cibmon_SOURCES = cibmon.c
cibmon_LDADD = $(COMMONLIBS)
clean-generic:
rm -f *.log *.debug *.xml *~
install-exec-local:
# cp -f $(top_srcdir)/crm/cib/cib.pam $(DESTDIR)/etc/pam.d/cib
uninstall-local:
diff --git a/crm/crmd/Makefile.am b/crm/crmd/Makefile.am
index d7560349dd..0ed9fc2849 100644
--- a/crm/crmd/Makefile.am
+++ b/crm/crmd/Makefile.am
@@ -1,91 +1,91 @@
#
# 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)
EXTRA_DIST =
hadir = $(sysconfdir)/ha.d
halibdir = $(libdir)/@HB_PKG@
commmoddir = $(halibdir)/modules/comm
havarlibdir = $(localstatedir)/lib/@HB_PKG@
# sockets with path
crmdir = $(havarlibdir)/crm
apigid = @HA_APIGID@
crmuid = @HA_CCMUID@
-COMMONLIBS = $(CRM_DEBUG_LIBS) \
- $(top_builddir)/lib/clplumbing/libplumb.la \
- $(top_builddir)/lib/pils/libpils.la \
- $(top_builddir)/lib/crm/common/libcrmcommon.la \
- $(top_builddir)/lib/crm/pengine/libpe_rules.la \
- $(top_builddir)/lib/crm/cib/libcib.la \
- $(top_builddir)/lib/apphb/libapphb.la \
- $(top_builddir)/lib/hbclient/libhbclient.la \
- $(GLIBLIB) \
+COMMONLIBS = $(CRM_DEBUG_LIBS) \
+ -lccmclient -lhbclient -lplumb \
+ -lcrmcommon -lpe_rules -lcib \
+ $(GLIBLIB) \
$(LIBRT)
LIBRT = @LIBRT@
-AM_CFLAGS = @CFLAGS@ \
- $(CRM_DEBUG_FLAGS)
+AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS)
+AM_LDFLAGS = -L$(top_builddir)/membership/ccm \
+ -L$(top_builddir)/lib/hbclient \
+ -L$(top_builddir)/lib/clplumbing \
+ -L$(top_builddir)/lib/lrm \
+ -L$(top_builddir)/lib/crm/common \
+ -L$(top_builddir)/lib/crm/pengine \
+ -L$(top_builddir)/lib/crm/cib \
+ @LDFLAGS@
## libraries
lib_LTLIBRARIES =
## binary progs
halib_PROGRAMS = crmd atest
## SOURCES
noinst_HEADERS = crmd.h crmd_fsa.h crmd_messages.h fsa_defines.h \
fsa_matrix.h fsa_proto.h crmd_utils.h crmd_callbacks.h \
crmd_lrm.h
atest_SOURCES = atest.c
atest_LDADD = $(COMMONLIBS)
crmd_SOURCES = main.c crmd.c \
fsa.c control.c messages.c ccm.c callbacks.c \
election.c join_client.c join_dc.c subsystems.c \
cib.c pengine.c tengine.c lrm.c \
utils.c misc.c
-crmd_LDADD = $(COMMONLIBS) \
- $(top_builddir)/lib/lrm/liblrm.la \
- $(top_builddir)/membership/ccm/libccmclient.la
+crmd_LDADD = $(COMMONLIBS) -llrm -lccmclient
clean-generic:
rm -f *.log *.debug *.xml *~
install-exec-local:
uninstall-local:
graphs: fsa_inputs.png fsa_inputs_by_action.png fsa_actions_by_state.png
%.png: %.dot
dot -Tpng $< > $@
%.dot : fsa_matrix.h make_dot.pl
perl $(top_srcdir)/crm/crmd/make_dot.pl $(top_srcdir)/crm/crmd/fsa_matrix.h $(top_builddir)/crm/crmd
diff --git a/crm/pengine/Makefile.am b/crm/pengine/Makefile.am
index 568c33f185..af900d1316 100644
--- a/crm/pengine/Makefile.am
+++ b/crm/pengine/Makefile.am
@@ -1,86 +1,87 @@
#
# 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)
hadir = $(sysconfdir)/ha.d
halibdir = $(libdir)/@HB_PKG@
commmoddir = $(halibdir)/modules/comm
havarlibdir = $(localstatedir)/lib/@HB_PKG@
pe_varlibdir = $(HA_VARLIBDIR)/$(HB_PKG)/pengine
# sockets with path
crmdir = $(havarlibdir)/crm
apigid = @HA_APIGID@
crmuid = @HA_CCMUID@
COMMONLIBS = $(CRM_DEBUG_LIBS) \
- $(top_builddir)/lib/clplumbing/libplumb.la \
- $(top_builddir)/lib/pils/libpils.la \
- $(top_builddir)/lib/crm/common/libcrmcommon.la \
- $(top_builddir)/lib/crm/pengine/libpe_status.la \
+ -lplumb -lcrmcommon -lpe_status \
libpengine.la \
$(GLIBLIB) \
$(CURSESLIBS) \
$(LIBRT)
LIBRT = @LIBRT@
AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS)
+AM_LDFLAGS = -L$(top_builddir)/lib/clplumbing \
+ -L$(top_builddir)/lib/crm/common \
+ -L$(top_builddir)/lib/crm/pengine \
+ @LDFLAGS@
## libraries
lib_LTLIBRARIES = libpengine.la
## binary progs
halib_PROGRAMS = ptest pengine
## SOURCES
noinst_HEADERS = allocate.h utils.h pengine.h
#utils.h pengine.h
libpengine_la_LDFLAGS = -version-info 3:0:0
# -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version
libpengine_la_SOURCES = pengine.c allocate.c utils.c \
native.c group.c clone.c master.c graph.c
pengine_SOURCES = main.c
pengine_LDADD = $(COMMONLIBS) $(top_builddir)/lib/crm/cib/libcib.la
# libcib for get_object_root()
# $(top_builddir)/lib/hbclient/libhbclient.la
ptest_SOURCES = ptest.c
ptest_LDADD = $(COMMONLIBS) \
$(top_builddir)/lib/crm/cib/libcib.la \
$(top_builddir)/lib/crm/transition/libtransitioner.la
clean-generic:
rm -f *.log *.debug *~ .gres.* testcases/.gres.*
install-exec-local:
$(mkinstalldirs) $(DESTDIR)/$(pe_varlibdir)
-chown $(HA_CCMUSER) $(DESTDIR)/$(pe_varlibdir)
-chgrp $(HA_APIGROUP) $(DESTDIR)/$(pe_varlibdir)
-chmod 750 $(DESTDIR)/$(pe_varlibdir)
uninstall-local:
diff --git a/crm/tengine/Makefile.am b/crm/tengine/Makefile.am
index 74a9c980fc..3d33923d76 100644
--- a/crm/tengine/Makefile.am
+++ b/crm/tengine/Makefile.am
@@ -1,69 +1,66 @@
#
# 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)
hadir = $(sysconfdir)/ha.d
halibdir = $(libdir)/@HB_PKG@
commmoddir = $(halibdir)/modules/comm
havarlibdir = $(localstatedir)/lib/@HB_PKG@
crmdir = $(havarlibdir)/crm
COMMONLIBS = $(CRM_DEBUG_LIBS) \
- $(top_builddir)/lib/clplumbing/libplumb.la \
- $(top_builddir)/lib/pils/libpils.la \
- $(top_builddir)/lib/crm/common/libcrmcommon.la \
- $(top_builddir)/lib/crm/cib/libcib.la \
- $(top_builddir)/lib/apphb/libapphb.la \
- $(top_builddir)/lib/hbclient/libhbclient.la \
+ -lplumb -lcrmcommon -lcib \
$(GLIBLIB) \
$(LIBRT)
LIBRT = @LIBRT@
AM_CFLAGS = @CFLAGS@ $(CRM_DEBUG_FLAGS)
+AM_LDFLAGS = -L$(top_builddir)/lib/clplumbing \
+ -L$(top_builddir)/lib/fencing \
+ -L$(top_builddir)/lib/crm/common \
+ -L$(top_builddir)/lib/crm/cib \
+ -L$(top_builddir)/lib/crm/transition \
+ @LDFLAGS@
## binary progs
halib_PROGRAMS = tengine ttest
## SOURCES
noinst_HEADERS = tengine.h te_callbacks.h
tengine_SOURCES = actions.c events.c utils.c callbacks.c main.c
-tengine_LDADD = $(COMMONLIBS) \
- $(top_builddir)/lib/fencing/libstonithd.la \
- $(top_builddir)/lib/crm/transition/libtransitioner.la
+tengine_LDADD = $(COMMONLIBS) -lstonithd -ltransitioner
ttest_SOURCES = actions.c events.c utils.c callbacks.c ttest.c
-ttest_LDADD = $(COMMONLIBS) \
- $(top_builddir)/lib/fencing/libstonithd.la \
- $(top_builddir)/lib/crm/transition/libtransitioner.la
+ttest_LDADD = $(COMMONLIBS) -lstonithd -ltransitioner
clean-generic:
rm -f *.log *.debug *~
install-exec-local:
uninstall-local:
diff --git a/lib/crm/common/xml.c b/lib/crm/common/xml.c
index 070aef5ffc..1a74d732ca 100644
--- a/lib/crm/common/xml.c
+++ b/lib/crm/common/xml.c
@@ -1,2549 +1,2550 @@
/*
* 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 <lha_internal.h>
#include <sys/param.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.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 <clplumbing/md5.h>
#if HAVE_BZLIB_H
# include <bzlib.h>
#endif
#define XML_BUFFER_SIZE 4096
int is_comment_start(const char *input, size_t offset, size_t max);
int is_comment_end(const char *input, size_t offset, size_t max);
gboolean drop_comments(const char *input, size_t *offset, size_t max);
void dump_array(
int log_level, const char *message, const char **array, int depth);
int print_spaces(char *buffer, int spaces);
int log_data_element(const char *function, const char *prefix, int log_level,
int depth, const crm_data_t *data, gboolean formatted);
int dump_data_element(
int depth, char **buffer, const crm_data_t *data, gboolean formatted);
crm_data_t *parse_xml(const char *input, size_t *offset);
int get_tag_name(const char *input, size_t offset, size_t max);
int get_attr_name(const char *input, size_t offset, size_t max);
int get_attr_value(const char *input, size_t offset, size_t max);
gboolean can_prune_leaf(crm_data_t *xml_node);
void diff_filter_context(int context, int upper_bound, int lower_bound,
crm_data_t *xml_node, crm_data_t *parent);
int in_upper_context(int depth, int context, crm_data_t *xml_node);
crm_data_t *
find_xml_node(crm_data_t *root, const char * search_path, gboolean must_find)
{
if(must_find || root != NULL) {
crm_validate_data(root);
}
if(search_path == NULL) {
crm_warn("Will never find <NULL>");
return NULL;
}
xml_child_iter_filter(
root, a_child, search_path,
/* crm_debug_5("returning node (%s).", crm_element_name(a_child)); */
crm_log_xml(LOG_DEBUG_5, "found:", a_child);
crm_log_xml(LOG_DEBUG_6, "in:", root);
crm_validate_data(a_child);
return a_child;
);
if(must_find) {
crm_warn("Could not find %s in %s.", search_path, crm_element_name(root));
} else if(root != NULL) {
crm_debug_3("Could not find %s in %s.", search_path, crm_element_name(root));
} else {
crm_debug_3("Could not find %s in <NULL>.", search_path);
}
return NULL;
}
crm_data_t*
find_xml_node_nested(crm_data_t *root, const char **search_path, int len)
{
int j;
gboolean is_found = TRUE;
crm_data_t *match = NULL;
crm_data_t *lastMatch = root;
crm_validate_data(root);
if(search_path == NULL || search_path[0] == 0) {
crm_warn("Will never find NULL");
return NULL;
}
dump_array(LOG_DEBUG_5, "Looking for.", search_path, len);
for (j=0; j < len; ++j) {
if (search_path[j] == NULL) {
/* a NULL also means stop searching */
break;
}
match = find_xml_node(lastMatch, search_path[j], FALSE);
if(match == NULL) {
is_found = FALSE;
break;
} else {
lastMatch = match;
}
}
if (is_found) {
crm_debug_5("returning node (%s).",
crm_element_name(lastMatch));
crm_log_xml_debug_5(lastMatch, "found\t%s");
crm_log_xml_debug_5(root, "in \t%s");
crm_validate_data(lastMatch);
return lastMatch;
}
dump_array(LOG_DEBUG_2,
"Could not find the full path to the node you specified.",
search_path, len);
crm_debug_2("Closest point was node (%s) starting from %s.",
crm_element_name(lastMatch), crm_element_name(root));
return NULL;
}
const char *
get_xml_attr_nested(crm_data_t *parent,
const char **node_path, int length,
const char *attr_name, gboolean error)
{
const char *attr_value = NULL;
crm_data_t *attr_parent = NULL;
if(error || parent != NULL) {
crm_validate_data(parent);
}
if(parent == NULL) {
crm_debug_3("Can not find attribute %s in NULL parent",attr_name);
return NULL;
}
if(attr_name == NULL || attr_name[0] == 0) {
crm_err("Can not find attribute with no name in %s",
crm_element_name(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 || attr_value[0] == 0) && error) {
crm_err("No value present for %s at %s",
attr_name, crm_element_name(attr_parent));
return NULL;
}
return attr_value;
}
crm_data_t*
find_entity(crm_data_t *parent, const char *node_name, const char *id)
{
crm_validate_data(parent);
xml_child_iter_filter(
parent, a_child, node_name,
if(id == NULL || crm_str_eq(id, ID(a_child), TRUE)) {
crm_debug_4("returning node (%s).",
crm_element_name(a_child));
return a_child;
}
);
crm_debug_3("node <%s id=%s> not found in %s.",
node_name, id, crm_element_name(parent));
return NULL;
}
void
copy_in_properties(crm_data_t* target, const crm_data_t *src)
{
int value_len = 0;
char *incr_value = NULL;
char *new_value = NULL;
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,
/* if the value is name followed by "++" we need
* to increment the existing value
*/
new_value = NULL;
incr_value = NULL;
if(strstr(local_prop_value, "++") > local_prop_value) {
int old_int = 0;
const char *old_value = NULL;
value_len = strlen(local_prop_value);
crm_malloc0(incr_value, value_len+2);
sprintf(incr_value, "%s++", local_prop_name);
if(safe_str_eq(local_prop_value, incr_value)) {
old_value = crm_element_value(
target, local_prop_name);
old_int = crm_parse_int(old_value, "0");
new_value = crm_itoa(old_int + 1);
local_prop_value = new_value;
}
}
crm_xml_add(target, local_prop_name, local_prop_value);
crm_free(incr_value);
crm_free(new_value);
);
crm_validate_data(target);
}
return;
}
crm_data_t*
add_node_copy(crm_data_t *parent, const crm_data_t *src_node)
{
const char *name = NULL;
crm_data_t *child = NULL;
CRM_CHECK(src_node != NULL, return NULL);
crm_validate_data(src_node);
name = crm_element_name(src_node);
CRM_CHECK(name != NULL, return NULL);
child = create_xml_node(parent, name);
copy_in_properties(child, src_node);
xml_child_iter(src_node, src_child,
add_node_copy(child, src_child);
);
return child;
}
int
add_node_nocopy(crm_data_t *parent, const char *name, crm_data_t *child)
{
int next = 0;
crm_validate_data(parent);
crm_validate_data(child);
if(name == NULL) {
name = crm_element_name(child);
}
CRM_ASSERT(name != NULL && name[0] != 0);
if (parent->nfields >= parent->nalloc
&& ha_msg_expand(parent) != HA_OK ){
crm_err("Parent expansion failed");
return HA_FAIL;
}
next = parent->nfields;
parent->names[next] = crm_strdup(name);
parent->nlens[next] = strlen(name);
parent->values[next] = child;
parent->vlens[next] = sizeof(struct ha_msg);
parent->types[next] = FT_UNCOMPRESS;
parent->nfields++;
return HA_OK;
}
const char *
crm_xml_add(crm_data_t* node, const char *name, const char *value)
{
const char *parent_name = NULL;
if(node != NULL) {
parent_name = crm_element_name(node);
}
crm_debug_5("[%s] Setting %s to %s", crm_str(parent_name), name, value);
if (name == NULL || name[0] == 0) {
} else if(node == NULL) {
} else if(parent_name == NULL && strcasecmp(name, F_XML_TAGNAME) != 0) {
} else if (value == NULL || value[0] == 0) {
xml_remove_prop(node, name);
return NULL;
} else {
const char *new_value = NULL;
crm_validate_data(node);
ha_msg_mod(node, name, value);
new_value = crm_element_value(node, name);
return new_value;
}
return NULL;
}
const char *
crm_xml_add_int(crm_data_t* node, const char *name, int value)
{
const char *parent_name = NULL;
if(node != NULL) {
parent_name = crm_element_name(node);
}
crm_debug_5("[%s] Setting %s to %d", crm_str(parent_name), name, value);
if (name == NULL || name[0] == 0) {
} else if(node == NULL) {
} else if(parent_name == NULL && strcasecmp(name, F_XML_TAGNAME) != 0) {
} else {
crm_validate_data(node);
ha_msg_mod_int(node, name, value);
return crm_element_value(node, name);
}
return NULL;
}
crm_data_t*
create_xml_node(crm_data_t *parent, const char *name)
{
const char *local_name = NULL;
const char *parent_name = NULL;
crm_data_t *ret_value = NULL;
if (name == NULL || name[0] == 0) {
ret_value = NULL;
} else {
local_name = name;
ret_value = ha_msg_new(3);
CRM_CHECK(ret_value != NULL, return NULL);
crm_xml_add(ret_value, F_XML_TAGNAME, name);
crm_validate_data(ret_value);
if(parent) {
crm_validate_data(parent);
parent_name = crm_element_name(parent);
crm_debug_5("Attaching %s to parent %s",
local_name, parent_name);
CRM_CHECK(HA_OK == ha_msg_addstruct(
parent, name, ret_value), return NULL);
crm_msg_del(ret_value);
crm_validate_data(parent);
ret_value = parent->values[parent->nfields-1];
}
}
crm_debug_5("Created node [%s [%s]]",
crm_str(parent_name), crm_str(local_name));
return ret_value;
}
void
free_xml_from_parent(crm_data_t *parent, crm_data_t *a_node)
{
CRM_CHECK(parent != NULL, return);
CRM_CHECK(a_node != NULL, return);
crm_validate_data(parent);
cl_msg_remove_value(parent, a_node);
crm_validate_data(parent);
}
void
add_xml_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_malloc0(since_epoch, 128);
if(since_epoch != NULL) {
sprintf(since_epoch, "%ld", (unsigned long)a_time);
ha_msg_mod(a_node, XML_ATTR_TSTAMP, since_epoch);
crm_validate_data(a_node);
crm_free(since_epoch);
}
}
crm_data_t*
copy_xml(const crm_data_t *src_node)
{
return add_node_copy(NULL, src_node);
}
crm_data_t*
string2xml(const char *input)
{
crm_data_t *output = parse_xml(input, NULL);
if(output != NULL) {
crm_validate_data(output);
}
return output;
}
crm_data_t *
stdin2xml(void)
{
size_t data_length = 0;
size_t read_chars = 0;
char *xml_buffer = NULL;
crm_data_t *xml_obj = NULL;
do {
crm_realloc(xml_buffer, XML_BUFFER_SIZE + data_length + 1);
read_chars = fread(xml_buffer + data_length, 1, XML_BUFFER_SIZE, stdin);
data_length += read_chars;
} while (read_chars > 0);
xml_buffer[data_length] = '\0';
xml_obj = string2xml(xml_buffer);
crm_free(xml_buffer);
crm_log_xml_debug_3(xml_obj, "Created fragment");
return xml_obj;
}
crm_data_t*
file2xml(FILE *input, gboolean compressed)
{
char *buffer = NULL;
gboolean work_done = FALSE;
crm_data_t *new_obj = NULL;
size_t length = 0, read_len = 0;
if(input == NULL) {
crm_err("No file to read");
return NULL;
}
if(compressed) {
#if HAVE_BZLIB_H
int rc = 0;
BZFILE *bz_file = BZ2_bzReadOpen(&rc, input, 0, 0, NULL, 0);
if ( rc != BZ_OK ) {
BZ2_bzReadClose ( &rc, bz_file);
return NULL;
}
rc = BZ_OK;
while ( rc == BZ_OK ) {
crm_realloc(buffer, XML_BUFFER_SIZE + length + 1);
read_len = BZ2_bzRead (
&rc, bz_file, buffer + length, XML_BUFFER_SIZE);
crm_debug_5("Read %ld bytes from file: %d",
(long)read_len, rc);
if ( rc == BZ_OK || rc == BZ_STREAM_END) {
length += read_len;
}
}
buffer[length] = '\0';
read_len = length;
if ( rc != BZ_STREAM_END ) {
crm_err("Couldnt read compressed xml from file");
crm_free(buffer);
}
BZ2_bzReadClose (&rc, bz_file);
if(buffer == NULL) {
return NULL;
}
work_done = TRUE;
#else
crm_err("Cannot read compressed files:"
" bzlib was not available at compile time");
#endif
}
if(work_done == FALSE) {
int start = 0;
start = ftell(input);
fseek(input, 0L, SEEK_END);
length = ftell(input);
fseek(input, 0L, start);
CRM_ASSERT(start == ftell(input));
crm_debug_3("Reading %ld bytes from file", (long)length);
crm_malloc0(buffer, (length+1));
read_len = fread(buffer, 1, length, input);
}
/* see how big the file is */
if(read_len != length) {
crm_err("Calculated and read bytes differ: %ld vs. %ld",
(long)length, (long)read_len);
} else if(length > 0) {
new_obj = string2xml(buffer);
} else {
crm_warn("File contained no XML");
}
crm_free(buffer);
return new_obj;
}
void
dump_array(int log_level, const char *message, const char **array, int depth)
{
int j;
if(message != NULL) {
do_crm_log(log_level, "%s", message);
}
do_crm_log(log_level, "Contents of the array:");
if(array == NULL || array[0] == NULL || depth == 0) {
do_crm_log(log_level, "\t<empty>");
return;
}
for (j=0; j < depth && array[j] != NULL; j++) {
if (array[j] == NULL) { break; }
do_crm_log(log_level, "\t--> (%s).", array[j]);
}
}
int
write_xml_file(crm_data_t *xml_node, const char *filename, gboolean compress)
{
int res = 0;
time_t now;
char *buffer = NULL;
char *now_str = NULL;
gboolean is_done = FALSE;
FILE *file_output_strm = NULL;
static mode_t cib_mode = S_IRUSR|S_IWUSR;
CRM_CHECK(filename != NULL, return -1);
crm_debug_3("Writing XML out to %s", filename);
crm_validate_data(xml_node);
if (xml_node == NULL) {
crm_err("Cannot write NULL to %s", filename);
return -1;
}
crm_validate_data(xml_node);
crm_log_xml_debug_4(xml_node, "Writing out");
crm_validate_data(xml_node);
now = time(NULL);
now_str = ctime(&now);
now_str[24] = EOS; /* replace the newline */
crm_xml_add(xml_node, XML_CIB_ATTR_WRITTEN, now_str);
crm_validate_data(xml_node);
buffer = dump_xml_formatted(xml_node);
CRM_CHECK(buffer != NULL && strlen(buffer) > 0, return -1);
/* establish the file with correct permissions */
file_output_strm = fopen(filename, "w");
if(file_output_strm == NULL) {
cl_perror("Cannot open %s for writing", filename);
crm_free(buffer);
return -1;
}
fclose(file_output_strm);
chmod(filename, cib_mode);
/* now write it */
file_output_strm = fopen(filename, "w");
if(file_output_strm == NULL) {
cl_perror("Cannot write to %s", filename);
crm_free(buffer);
return -1;
}
if(compress) {
#if HAVE_BZLIB_H
int rc = BZ_OK;
BZFILE *bz_file = NULL;
unsigned int in = 0, out = 0;
is_done = TRUE;
bz_file = BZ2_bzWriteOpen(&rc, file_output_strm, 5,0,0);
if(rc != BZ_OK) {
is_done = FALSE;
crm_err("bzWriteOpen failed: %d", rc);
}
if(is_done) {
BZ2_bzWrite(&rc,bz_file,buffer,strlen(buffer));
if(rc != BZ_OK) {
crm_err("bzWrite() failed: %d", rc);
is_done = FALSE;
}
}
if(is_done) {
BZ2_bzWriteClose(&rc, bz_file, 0, &in, &out);
if(rc != BZ_OK) {
crm_err("bzWriteClose() failed: %d",rc);
is_done = FALSE;
} else {
crm_debug_2("%s: In: %d, out: %d",
filename, in, out);
}
}
#else
crm_err("Cannot write compressed files:"
" bzlib was not available at compile time");
#endif
}
if(is_done == FALSE) {
res = fprintf(file_output_strm, "%s", buffer);
if(res < 0) {
cl_perror("Cannot write output to %s", filename);
}
if(fflush(file_output_strm) == EOF || fsync(fileno(file_output_strm)) < 0) {
cl_perror("fflush or fsync error on %s", filename);
fclose(file_output_strm);
+ crm_free(buffer);
return -1;
}
}
fclose(file_output_strm);
crm_free(buffer);
crm_debug_3("Saved %d bytes to the Cib as XML", res);
return res;
}
void
print_xml_formatted(int log_level, const char *function,
const crm_data_t *msg, const char *text)
{
if(msg == NULL) {
do_crm_log(log_level, "%s: %s: NULL", function, crm_str(text));
return;
}
crm_validate_data(msg);
log_data_element(function, text, log_level, 0, msg, TRUE);
return;
}
crm_data_t *
get_message_xml(HA_Message *msg, const char *field)
{
crm_data_t *xml_node = NULL;
crm_data_t *tmp_node = NULL;
crm_validate_data(msg);
tmp_node = cl_get_struct(msg, field);
if(tmp_node != NULL) {
xml_node = copy_xml(tmp_node);
}
return xml_node;
}
gboolean
add_message_xml(HA_Message *msg, const char *field, const crm_data_t *xml)
{
crm_validate_data(xml);
crm_validate_data(msg);
CRM_CHECK(field != NULL, return FALSE);
ha_msg_addstruct_compress(msg, field, xml);
return TRUE;
}
char *
dump_xml_formatted(const crm_data_t *an_xml_node)
{
char *buffer = NULL;
char *mutable_ptr = NULL;
if(an_xml_node == NULL) {
return NULL;
}
crm_malloc0(buffer, 3*get_stringlen(an_xml_node));
mutable_ptr = buffer;
crm_validate_data(an_xml_node);
CRM_CHECK(dump_data_element(
0, &mutable_ptr, an_xml_node, TRUE) >= 0,
crm_crit("Could not dump the whole message"));
crm_debug_4("Dumped: %s", buffer);
return buffer;
}
char *
dump_xml_unformatted(const crm_data_t *an_xml_node)
{
char *buffer = NULL;
char *mutable_ptr = NULL;
crm_malloc0(buffer, 2*get_stringlen(an_xml_node));
mutable_ptr = buffer;
crm_validate_data(an_xml_node);
CRM_CHECK(dump_data_element(
0, &mutable_ptr, an_xml_node, FALSE) >= 0,
crm_crit("Could not dump the whole message"));
crm_debug_4("Dumped: %s", buffer);
return buffer;
}
#define update_buffer_head(buffer, len) if(len < 0) { \
(*buffer) = EOS; return -1; \
} else { \
buffer += len; \
}
int
print_spaces(char *buffer, int depth)
{
int lpc = 0;
int spaces = 2*depth;
/* <= so that we always print 1 space - prevents problems with syslog */
for(lpc = 0; lpc <= spaces; lpc++) {
if(sprintf(buffer, "%c", ' ') < 1) {
return -1;
}
buffer += 1;
}
return lpc;
}
int
log_data_element(
const char *function, const char *prefix, int log_level, int depth,
const crm_data_t *data, gboolean formatted)
{
int printed = 0;
int child_result = 0;
int has_children = 0;
char print_buffer[1000];
char *buffer = print_buffer;
const char *name = crm_element_name(data);
const char *hidden = NULL;
crm_debug_5("Dumping %s...", name);
crm_validate_data(data);
if(data == NULL) {
crm_warn("No data to dump as XML");
return 0;
} else if(name == NULL && depth == 0) {
xml_child_iter(
data, a_child,
child_result = log_data_element(
function, prefix, log_level, depth, a_child, formatted);
if(child_result < 0) {
return child_result;
}
);
return 0;
} else if(name == NULL) {
crm_err("Cannot dump NULL element at depth %d", depth);
return -1;
}
if(formatted) {
printed = print_spaces(buffer, depth);
update_buffer_head(buffer, printed);
}
printed = sprintf(buffer, "<%s", name);
update_buffer_head(buffer, printed);
hidden = crm_element_value(data, "hidden");
xml_prop_iter(
data, prop_name, prop_value,
if(prop_name == NULL) {
CRM_ASSERT(prop_name != NULL);
} else if(safe_str_eq(F_XML_TAGNAME, prop_name)) {
continue;
} else if(hidden != NULL
&& prop_name[0] != 0
&& strstr(hidden, prop_name) != NULL) {
prop_value = "*****";
}
crm_debug_5("Dumping <%s %s=\"%s\"...",
name, prop_name, prop_value);
printed = sprintf(buffer, " %s=\"%s\"", prop_name, prop_value);
update_buffer_head(buffer, printed);
);
xml_child_iter(
data, child,
if(child != NULL) {
has_children++;
break;
}
);
printed = sprintf(buffer, "%s>", has_children==0?"/":"");
update_buffer_head(buffer, printed);
do_crm_log(log_level, "%s: %s%s",
function, prefix?prefix:"", print_buffer);
buffer = print_buffer;
if(has_children == 0) {
return 0;
}
xml_child_iter(
data, a_child,
child_result = log_data_element(
function, prefix, log_level, depth+1, a_child, formatted);
if(child_result < 0) { return -1; }
);
if(formatted) {
printed = print_spaces(buffer, depth);
update_buffer_head(buffer, printed);
}
do_crm_log(log_level, "%s: %s%s</%s>",
function, prefix?prefix:"", print_buffer, name);
crm_debug_5("Dumped %s...", name);
return has_children;
}
int
dump_data_element(
int depth, char **buffer, const crm_data_t *data, gboolean formatted)
{
int printed = 0;
int child_result = 0;
int has_children = 0;
const char *name = NULL;
CRM_ASSERT(data != NULL);
CRM_ASSERT(buffer != NULL && *buffer != NULL);
name = crm_element_name(data);
if(name == NULL && depth == 0) {
name = "__fake__";
}
CRM_ASSERT(name != NULL);
crm_debug_5("Dumping %s...", name);
if(formatted) {
printed = print_spaces(*buffer, depth);
update_buffer_head(*buffer, printed);
}
printed = sprintf(*buffer, "<%s", name);
update_buffer_head(*buffer, printed);
has_children = xml_has_children(data);
xml_prop_iter(data, prop_name, prop_value,
crm_debug_5("Dumping <%s %s=\"%s\"...",
name, prop_name, prop_value);
printed = sprintf(*buffer, " %s=\"%s\"", prop_name, prop_value);
update_buffer_head(*buffer, printed);
);
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,
child_result = dump_data_element(
depth+1, buffer, child, formatted);
if(child_result < 0) { return -1; }
);
if(formatted) {
printed = print_spaces(*buffer, depth);
update_buffer_head(*buffer, printed);
}
printed = sprintf(*buffer, "</%s>%s", name, formatted?"\n":"");
update_buffer_head(*buffer, printed);
crm_debug_5("Dumped %s...", name);
return has_children;
}
gboolean
xml_has_children(const crm_data_t *xml_root)
{
crm_validate_data(xml_root);
xml_child_iter(
xml_root, a_child,
return TRUE;
);
return FALSE;
}
void
xml_validate(const crm_data_t *xml_root)
{
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
|| xml_root->types[lpc] == FT_UNCOMPRESS) {
crm_validate_data(child);
} else if(xml_root->types[lpc] == FT_STRING) {
CRM_ASSERT(cl_is_allocated(child) == 1);
/* } else { */
/* CRM_CHECK(FALSE); */
}
}
}
const char *
crm_element_value(const crm_data_t *data, const char *name)
{
const char *value = NULL;
crm_validate_data(data);
value = cl_get_string(data, name);
#if XML_PARANOIA_CHECKS
CRM_CHECK(value == NULL || cl_is_allocated(value) == 1, return NULL);
#endif
return value;
}
char *
crm_element_value_copy(const crm_data_t *data, const char *name)
{
char *value_copy = NULL;
const char *value = crm_element_value(data, name);
if(value != NULL) {
value_copy = crm_strdup(value);
}
return value_copy;
}
const char *
crm_element_name(const crm_data_t *data)
{
#if CRM_DEV_BUILD
crm_validate_data(data);
#endif
return cl_get_string(data, F_XML_TAGNAME);
}
void
xml_remove_prop(crm_data_t *obj, const char *name)
{
if(crm_element_value(obj, name) != NULL) {
cl_msg_remove(obj, name);
}
}
int
get_tag_name(const char *input, size_t offset, size_t max)
{
char ch = 0;
size_t lpc = offset;
const char *error = NULL;
gboolean do_special = FALSE;
for(; error == NULL && lpc < max; lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c [%d]", ch, (int)lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '?':
if(lpc == 0) {
/* weird xml tag that we dont care about */
do_special = TRUE;
} else {
goto out;
}
break;
case '/':
case '>':
case '\t':
case '\n':
case ' ':
if(!do_special) {
goto out;
}
break;
default:
if(do_special) {
} else if('a' <= ch && ch <= 'z') {
} else if('A' <= ch && ch <= 'Z') {
} else if(ch == '_') {
} else if(ch == '-') {
} else {
error = "bad character, not in [a-zA-Z_-]";
}
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return 0;
out:
CRM_ASSERT(lpc > offset);
return lpc - offset;
}
int
get_attr_name(const char *input, size_t offset, size_t max)
{
char ch = 0;
size_t lpc = offset;
const char *error = NULL;
for(; error == NULL && lpc < max; lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c[%d]", ch, (int)lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '\t':
case '\n':
case ' ':
error = "unexpected whitespace";
break;
case '=':
return lpc - offset;
default:
if('a' <= ch && ch <= 'z') {
} else if('A' <= ch && ch <= 'Z') {
} else if('0' <= ch && ch <= '9') {
} else if(ch == '_') {
} else if(ch == '-') {
} else {
error = "bad character, not in [a-zA-Z0-9_-]";
}
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
int
get_attr_value(const char *input, size_t offset, size_t max)
{
char ch = 0;
size_t lpc = offset;
const char *error = NULL;
for(; error == NULL && lpc < max; lpc++) {
ch = input[lpc];
crm_debug_5("Processing char %c [%d]", ch, (int)lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '\\':
if(input[lpc+1] == '"') {
/* skip over the next char */
lpc++;
break;
}
/*fall through*/
case '"':
return lpc - offset;
default:
break;
}
}
crm_err("Error parsing token near %.15s: %s", input, crm_str(error));
return -1;
}
int
is_comment_start(const char *input, size_t offset, size_t max)
{
size_t remaining = max - offset;
CRM_CHECK(input != NULL, return 0);
CRM_CHECK(offset < max, return 0);
input += offset;
if(remaining > 4
&& input[0] == '<'
&& input[1] == '!'
&& input[2] == '-'
&& input[3] == '-') {
crm_debug_6("Found comment start: <!--");
return 4;
} else if(remaining > 2
&& input[0] == '<'
&& input[1] == '!') {
crm_debug_6("Found comment start: <!");
return 2;
} else if(remaining > 2
&& input[0] == '<'
&& input[1] == '?') {
crm_debug_6("Found comment start: <?");
return 2;
}
if(remaining > 3) {
crm_debug_6("Not comment start: %c%c%c%c", input[0], input[1], input[2], input[3]);
} else {
crm_debug_6("Not comment start");
}
return 0;
}
int
is_comment_end(const char *input, size_t offset, size_t max)
{
size_t remaining = max - offset;
CRM_CHECK(input != NULL, return 0);
input += offset;
if(remaining > 2
&& input[0] == '-'
&& input[1] == '-'
&& input[2] == '>') {
crm_debug_6("Found comment end: -->");
return 3;
} else if(remaining > 1
&& input[0] == '?'
&& input[1] == '>') {
crm_debug_6("Found comment end: ?>");
return 2;
}
if(remaining > 2) {
crm_debug_6("Not comment end: %c%c%c", input[0], input[1], input[2]);
} else {
crm_debug_6("Not comment end");
}
return 0;
}
static gboolean
drop_whitespace(const char *input, size_t *offset, size_t max)
{
char ch = 0;
size_t lpc = *offset;
gboolean more = TRUE;
const char *our_input = input;
if(input == NULL) {
return FALSE;
}
while(lpc < max && more) {
ch = our_input[lpc];
crm_debug_6("Processing char %c[%d]", ch, (int)lpc);
if(isspace(ch)) {
lpc++;
} else {
more = FALSE;
}
}
crm_debug_4("Finished processing whitespace");
if(lpc > *offset) {
crm_debug_5("Skipped %d whitespace chars", (int)(lpc - *offset));
}
(*offset) = lpc;
return FALSE;
}
gboolean
drop_comments(const char *input, size_t *offset, size_t max)
{
gboolean more = TRUE;
gboolean in_directive = FALSE;
int in_comment = FALSE;
size_t lpc = 0;
int tag_len = 0;
char ch = 0;
if(input == NULL) {
return FALSE;
}
CRM_ASSERT(offset != NULL);
lpc = *offset;
while(lpc < max && more) {
ch = input[lpc];
crm_debug_6("Processing char [%d]: %c ", (int)lpc, ch);
switch(ch) {
case 0:
if(in_comment == FALSE) {
more = FALSE;
} else {
crm_err("unexpected EOS");
crm_warn("Parsing error at or before: %s", input+lpc);
}
break;
case '<':
tag_len = is_comment_start(input, lpc, max);
if(tag_len > 0) {
if(in_comment) {
crm_err("Nested XML comments are not supported!");
crm_warn("Parsing error at or before: %s", input+lpc);
}
in_comment = TRUE;
lpc+=tag_len;
if(tag_len == 2 && input[lpc-1] == '!') {
in_directive = TRUE;
}
} else if(in_comment == FALSE){
more = FALSE;
} else {
lpc++;
}
break;
case '>':
lpc++;
if(in_directive) {
in_directive = FALSE;
in_comment = FALSE;
}
break;
case '-':
case '?':
tag_len = is_comment_end(input, lpc, max);
if(tag_len > 0) {
lpc+=tag_len;
in_comment = FALSE;
} else {
lpc++;
}
break;
case ' ':
case '\t':
case '\n':
case '\r':
lpc++;
break;
default:
lpc++;
break;
}
}
crm_debug_4("Finished processing comments");
crm_debug_5("Skipped %d comment chars", (int)(lpc - *offset));
*offset = lpc;
return FALSE;
}
crm_data_t*
parse_xml(const char *input, size_t *offset)
{
char ch = 0;
size_t lpc = 0, len = 0, max = 0;
char *tag_name = NULL;
char *attr_name = NULL;
char *attr_value = NULL;
gboolean more = TRUE;
gboolean were_comments = TRUE;
const char *error = NULL;
const char *our_input = input;
crm_data_t *new_obj = NULL;
if(input == NULL) {
return NULL;
}
if(offset != NULL) {
our_input = input + (*offset);
}
max = strlen(our_input);
were_comments = drop_comments(our_input, &lpc, max);
CRM_CHECK(our_input[lpc] == '<', return NULL);
lpc++;
len = get_tag_name(our_input, lpc, max);
crm_debug_5("Tag length: %d", (int)len);
CRM_CHECK(len > 0, return NULL);
crm_malloc0(tag_name, len+1);
strncpy(tag_name, our_input + lpc, len+1);
tag_name[len] = EOS;
crm_debug_4("Processing tag %s", tag_name);
new_obj = ha_msg_new(1);
ha_msg_add(new_obj, F_XML_TAGNAME, tag_name);
lpc += len;
for(; more && error == NULL && lpc < max; lpc++) {
ch = our_input[lpc];
crm_debug_5("Processing char %c[%d]", ch, (int)lpc);
switch(ch) {
case 0:
error = "unexpected EOS";
break;
case '/':
if(our_input[lpc+1] == '>') {
more = FALSE;
}
break;
case '<':
if(our_input[lpc+1] == '!') {
lpc--; /* allow the '<' to be processed */
drop_comments(our_input, &lpc, max);
lpc--; /* allow the '<' to be processed */
} else if(our_input[lpc+1] != '/') {
crm_data_t *child = NULL;
crm_debug_4("Start parsing child at %d...", (int)lpc);
lpc--;
child = parse_xml(our_input, &lpc);
if(child == NULL) {
error = "error parsing child";
break;
}
add_node_nocopy(new_obj, NULL, child);
/* ha_msg_addstruct_compress( */
/* new_obj, crm_element_name(child), child); */
crm_debug_4("Finished parsing child: %s",
crm_element_name(child));
if(our_input[lpc] == '<') {
lpc--; /* allow the '<' to be processed */
}
} else {
lpc += 2; /* </ */
len = get_tag_name(our_input, lpc, max);
if(len < 0) {
error = "couldnt find tag";
} else if(strncmp(our_input+lpc, tag_name, len) == 0) {
more = FALSE;
lpc += len;
if(our_input[lpc] != '>') {
error = "clase tag cannot contain attrs";
}
crm_debug_4("Finished parsing ourselves: %s",
crm_element_name(new_obj));
} else {
error = "Mismatching close tag";
crm_err("Expected: %s", tag_name);
}
}
break;
case '=':
lpc++; /* = */
/*fall through*/
case '"':
lpc++; /* " */
len = get_attr_value(our_input, lpc, max);
if(len < 0) {
error = "couldnt find attr_value";
} else {
crm_malloc0(attr_value, len+1);
strncpy(attr_value, our_input+lpc, len+1);
attr_value[len] = EOS;
lpc += len;
crm_debug_4("creating nvpair: <%s %s=\"%s\"...",
tag_name, attr_name, attr_value);
ha_msg_add(new_obj, attr_name, attr_value);
crm_free(attr_name);
crm_free(attr_value);
}
break;
case '>':
while(our_input[lpc+1] != '<') {
lpc++;
}
break;
case ' ':
case '\t':
case '\n':
case '\r':
break;
default:
len = get_attr_name(our_input, lpc, max);
if(len < 0) {
error = "couldnt find attr_name";
} else {
crm_malloc0(attr_name, len+1);
strncpy(attr_name, our_input+lpc, len+1);
attr_name[len] = EOS;
lpc += len;
crm_debug_4("found attr name: %s", attr_name);
lpc--; /* make sure the '=' is seen next time around */
}
break;
}
}
if(error) {
crm_err("Error parsing token: %s", error);
crm_err("Error at or before: %.20s", our_input+lpc-3);
return NULL;
}
if(offset == NULL) {
drop_comments(our_input, &lpc, max);
drop_whitespace(our_input, &lpc, max);
if(lpc < max) {
crm_err("Ignoring trailing characters in XML input.");
crm_err("Parsed %d characters of a possible %d. Trailing text was: ...\'%20s\'",
(int)lpc, (int)max, our_input+lpc);
}
}
crm_debug_4("Finished processing %s tag", tag_name);
crm_free(tag_name);
if(offset != NULL) {
(*offset) += lpc;
}
return new_obj;
}
void
log_xml_diff(unsigned int log_level, crm_data_t *diff, const char *function)
{
crm_data_t *added = find_xml_node(diff, "diff-added", FALSE);
crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE);
gboolean is_first = TRUE;
if(crm_log_level < log_level) {
/* nothing will ever be printed */
return;
}
xml_child_iter(
removed, child,
log_data_element(function, "-", log_level, 0, child, TRUE);
if(is_first) {
is_first = FALSE;
} else {
do_crm_log(log_level, " --- ");
}
);
is_first = TRUE;
xml_child_iter(
added, child,
log_data_element(function, "+", log_level, 0, child, TRUE);
if(is_first) {
is_first = FALSE;
} else {
do_crm_log(log_level, " --- ");
}
);
}
void
purge_diff_markers(crm_data_t *a_node)
{
CRM_CHECK(a_node != NULL, return);
xml_remove_prop(a_node, XML_DIFF_MARKER);
xml_child_iter(a_node, child,
purge_diff_markers(child);
);
}
gboolean
apply_xml_diff(crm_data_t *old, crm_data_t *diff, crm_data_t **new)
{
gboolean result = TRUE;
crm_data_t *added = find_xml_node(diff, "diff-added", FALSE);
crm_data_t *removed = find_xml_node(diff, "diff-removed", FALSE);
int root_nodes_seen = 0;
CRM_CHECK(new != NULL, return FALSE);
crm_debug_2("Substraction Phase");
xml_child_iter(removed, child_diff,
CRM_CHECK(root_nodes_seen == 0, result = FALSE);
if(root_nodes_seen == 0) {
*new = subtract_xml_object(old, child_diff, NULL);
}
root_nodes_seen++;
);
if(root_nodes_seen == 0) {
*new = copy_xml(old);
} else if(root_nodes_seen > 1) {
crm_err("(-) Diffs cannot contain more than one change set..."
" saw %d", root_nodes_seen);
result = FALSE;
}
root_nodes_seen = 0;
crm_debug_2("Addition Phase");
if(result) {
xml_child_iter(added, child_diff,
CRM_CHECK(root_nodes_seen == 0, result = FALSE);
if(root_nodes_seen == 0) {
add_xml_object(NULL, *new, child_diff);
}
root_nodes_seen++;
);
}
if(root_nodes_seen > 1) {
crm_err("(+) Diffs cannot contain more than one change set..."
" saw %d", root_nodes_seen);
result = FALSE;
} else if(result) {
int lpc = 0;
crm_data_t *intermediate = NULL;
crm_data_t *diff_of_diff = NULL;
crm_data_t *calc_added = NULL;
crm_data_t *calc_removed = NULL;
const char *value = NULL;
const char *name = NULL;
const char *version_attrs[] = {
XML_ATTR_NUMUPDATES,
XML_ATTR_GENERATION,
XML_ATTR_GENERATION_ADMIN
};
crm_debug_2("Verification Phase");
intermediate = diff_xml_object(old, *new, FALSE);
calc_added = find_xml_node(intermediate, "diff-added", FALSE);
calc_removed = find_xml_node(intermediate, "diff-removed", FALSE);
/* add any version details to the diff so they match */
for(lpc = 0; lpc < DIMOF(version_attrs); lpc++) {
name = version_attrs[lpc];
value = crm_element_value(added, name);
crm_xml_add(calc_added, name, value);
value = crm_element_value(removed, name);
crm_xml_add(calc_removed, name, value);
}
diff_of_diff = diff_xml_object(intermediate, diff, TRUE);
if(diff_of_diff != NULL) {
crm_notice("Diff application failed!");
crm_log_xml_debug(old, "diff:old");
crm_log_xml_debug(*new, "diff:new");
log_xml_diff(LOG_DEBUG, diff_of_diff, "diff:diff_of_diff");
log_xml_diff(LOG_INFO, intermediate, "diff:actual_diff");
result = FALSE;
}
free_xml(diff_of_diff);
free_xml(intermediate);
diff_of_diff = NULL;
intermediate = NULL;
}
if(result == FALSE) {
log_xml_diff(LOG_INFO, diff, "diff:input_diff");
log_data_element("diff:input", NULL, LOG_DEBUG_2, 0, old, TRUE);
/* CRM_CHECK(diff_of_diff != NULL); */
result = FALSE;
} else {
purge_diff_markers(*new);
}
return result;
}
crm_data_t *
diff_xml_object(crm_data_t *old, crm_data_t *new, gboolean suppress)
{
crm_data_t *diff = NULL;
crm_data_t *tmp1 = NULL;
crm_data_t *added = NULL;
crm_data_t *removed = NULL;
tmp1 = subtract_xml_object(old, new, "removed:top");
if(tmp1 != NULL) {
if(suppress && can_prune_leaf(tmp1)) {
ha_msg_del(tmp1);
} else {
diff = create_xml_node(NULL, "diff");
removed = create_xml_node(diff, "diff-removed");
added = create_xml_node(diff, "diff-added");
add_node_nocopy(removed, NULL, tmp1);
}
}
tmp1 = subtract_xml_object(new, old, "added:top");
if(tmp1 != NULL) {
if(suppress && can_prune_leaf(tmp1)) {
ha_msg_del(tmp1);
return diff;
}
if(diff == NULL) {
diff = create_xml_node(NULL, "diff");
}
if(removed == NULL) {
removed = create_xml_node(diff, "diff-removed");
}
if(added == NULL) {
added = create_xml_node(diff, "diff-added");
}
add_node_nocopy(added, NULL, tmp1);
}
return diff;
}
gboolean
can_prune_leaf(crm_data_t *xml_node)
{
gboolean can_prune = TRUE;
/* return FALSE; */
xml_prop_iter(xml_node, prop_name, prop_value,
if(safe_str_eq(prop_name, XML_ATTR_ID)) {
continue;
}
can_prune = FALSE;
);
xml_child_iter(xml_node, child,
if(can_prune_leaf(child)) {
cl_msg_remove_value(xml_node, child);
__counter--;
} else {
can_prune = FALSE;
}
);
return can_prune;
}
void
diff_filter_context(int context, int upper_bound, int lower_bound,
crm_data_t *xml_node, crm_data_t *parent)
{
crm_data_t *us = NULL;
crm_data_t *new_parent = parent;
const char *name = crm_element_name(xml_node);
CRM_CHECK(xml_node != NULL && name != NULL, return);
us = create_xml_node(parent, name);
xml_prop_iter(xml_node, prop_name, prop_value,
lower_bound = context;
crm_xml_add(us, prop_name, prop_value);
);
if(lower_bound >= 0 || upper_bound >= 0) {
crm_xml_add(us, XML_ATTR_ID, ID(xml_node));
new_parent = us;
} else {
upper_bound = in_upper_context(0, context, xml_node);
if(upper_bound >= 0) {
crm_xml_add(us, XML_ATTR_ID, ID(xml_node));
new_parent = us;
} else {
free_xml(us);
us = NULL;
}
}
xml_child_iter(us, child,
diff_filter_context(
context, upper_bound-1, lower_bound-1,
child, new_parent);
);
}
int
in_upper_context(int depth, int context, crm_data_t *xml_node)
{
gboolean has_attributes = FALSE;
if(context == 0) {
return 0;
}
xml_prop_iter(xml_node, prop_name, prop_value,
has_attributes = TRUE;
break;
);
if(has_attributes) {
return depth;
} else if(depth < context) {
xml_child_iter(xml_node, child,
if(in_upper_context(depth+1, context, child)) {
return depth;
}
);
}
return 0;
}
crm_data_t *
subtract_xml_object(crm_data_t *left, crm_data_t *right, const char *marker)
{
gboolean skip = FALSE;
gboolean differences = FALSE;
crm_data_t *diff = NULL;
crm_data_t *child_diff = NULL;
crm_data_t *right_child = NULL;
const char *id = NULL;
const char *name = NULL;
const char *value = NULL;
const char *right_val = NULL;
int lpc = 0;
const char *filter[] = {
XML_ATTR_ORIGIN,
XML_DIFF_MARKER,
XML_CIB_ATTR_WRITTEN,
};
static int filter_len = DIMOF(filter);
crm_log_xml(LOG_DEBUG_5, "left:", left);
crm_log_xml(LOG_DEBUG_5, "right:", right);
if(left == NULL) {
return NULL;
}
id = ID(left);
if(right == NULL) {
crm_data_t *deleted = NULL;
crm_debug_5("Processing <%s id=%s> (complete copy)",
crm_element_name(left), id);
deleted = copy_xml(left);
crm_xml_add(deleted, XML_DIFF_MARKER, marker);
return deleted;
}
name = crm_element_name(left);
/* sanity checks */
CRM_CHECK(name != NULL, return NULL);
/* these checks are costly haven't caught anything for a while */
/* CRM_CHECK(safe_str_eq(crm_element_name(left), */
/* crm_element_name(right)), return NULL); */
/* CRM_CHECK(safe_str_eq(id, ID(right)), return NULL); */
diff = create_xml_node(NULL, name);
/* changes to name/value pairs */
crm_debug_5("Processing <%s id=%s>", crm_str(name), id);
xml_prop_iter(left, prop_name, left_value,
if(crm_str_eq(prop_name, XML_ATTR_ID, TRUE)) {
continue;
}
skip = FALSE;
for(lpc = 0; skip == FALSE && lpc < filter_len; lpc++){
if(crm_str_eq(prop_name, filter[lpc], TRUE)) {
skip = TRUE;
}
}
if(skip) { continue; }
right_val = crm_element_value(right, prop_name);
if(right_val == NULL) {
differences = TRUE;
crm_xml_add(diff, prop_name, left_value);
crm_debug_6("\t%s: %s", crm_str(prop_name),
crm_str(left_value));
} else if(safe_str_eq(left_value, right_val)) {
crm_debug_5("\t%s: %s (removed)",
crm_str(prop_name),
crm_str(left_value));
} else {
differences = TRUE;
crm_xml_add(diff, prop_name, left_value);
crm_debug_5("\t%s: %s->%s",
crm_str(prop_name),
crm_str(left_value),
right_val);
}
);
/* changes to child objects */
crm_debug_3("Processing children of <%s id=%s>",crm_str(name),id);
xml_child_iter(
left, left_child,
right_child = find_entity(
right, crm_element_name(left_child), ID(left_child));
child_diff = subtract_xml_object(
left_child, right_child, marker);
if(child_diff != NULL) {
differences = TRUE;
add_node_nocopy(diff, NULL, child_diff);
}
);
if(differences == FALSE) {
/* check for XML_DIFF_MARKER in a child */
xml_child_iter(
right, right_child,
value = crm_element_value(right_child, XML_DIFF_MARKER);
if(value != NULL && safe_str_eq(value, "removed:top")) {
crm_debug("Found the root of the deletion: %s", name);
crm_log_xml_debug(right_child, "deletion");
differences = TRUE;
break;
}
);
}
if(differences == FALSE) {
free_xml(diff);
crm_debug_5("\tNo changes to <%s id=%s>", crm_str(name), id);
return NULL;
}
crm_xml_add(diff, XML_ATTR_ID, id);
return diff;
}
int
add_xml_object(crm_data_t *parent, crm_data_t *target, const crm_data_t *update)
{
const char *object_id = NULL;
const char *object_name = NULL;
crm_log_xml(LOG_DEBUG_5, "update:", update);
crm_log_xml(LOG_DEBUG_5, "target:", target);
CRM_CHECK(update != NULL, return 0);
object_name = crm_element_name(update);
object_id = ID(update);
CRM_CHECK(object_name != NULL, return 0);
if(target == NULL && object_id == NULL) {
/* placeholder object */
target = find_xml_node(parent, object_name, FALSE);
} else if(target == NULL) {
target = find_entity(parent, object_name, object_id);
}
if(target == NULL) {
target = create_xml_node(parent, object_name);
CRM_CHECK(target != NULL, return 0);
crm_debug_2("Added <%s%s%s/>", crm_str(object_name),
object_id?" id=":"", object_id?object_id:"");
} else {
crm_debug_3("Found node <%s%s%s/> to update",
crm_str(object_name),
object_id?" id=":"", object_id?object_id:"");
}
copy_in_properties(target, update);
xml_child_iter(
update, a_child,
crm_debug_4("Updating child <%s id=%s>",
crm_element_name(a_child), ID(a_child));
add_xml_object(target, NULL, a_child);
);
crm_debug_3("Finished with <%s id=%s>",
crm_str(object_name), crm_str(object_id));
return 0;
}
gboolean
update_xml_child(crm_data_t *child, crm_data_t *to_update)
{
gboolean can_update = TRUE;
CRM_CHECK(child != NULL, return FALSE);
CRM_CHECK(to_update != NULL, return FALSE);
if(safe_str_neq(crm_element_name(to_update), crm_element_name(child))) {
can_update = FALSE;
} else if(safe_str_neq(ID(to_update), ID(child))) {
can_update = FALSE;
} else if(can_update) {
crm_log_xml_debug_2(child, "Update match found...");
add_xml_object(NULL, child, to_update);
}
xml_child_iter(
child, child_of_child,
/* only update the first one */
if(can_update) {
break;
}
can_update = update_xml_child(child_of_child, to_update);
);
return can_update;
}
int
find_xml_children(crm_data_t **children, crm_data_t *root,
const char *tag, const char *field, const char *value,
gboolean search_matches)
{
int match_found = 0;
CRM_CHECK(root != NULL, return FALSE);
CRM_CHECK(children != NULL, return FALSE);
if(tag != NULL && safe_str_neq(tag, crm_element_name(root))) {
} else if(value != NULL
&& safe_str_neq(value, crm_element_value(root, field))) {
} else {
if(*children == NULL) {
*children = create_xml_node(NULL, __FUNCTION__);
}
add_node_copy(*children, root);
match_found = 1;
}
if(search_matches || match_found == 0) {
xml_child_iter(
root, child,
match_found += find_xml_children(
children, child, tag, field, value,
search_matches);
);
}
return match_found;
}
gboolean
replace_xml_child(crm_data_t *parent, crm_data_t *child, crm_data_t *update, gboolean delete_only)
{
gboolean can_delete = FALSE;
const char *up_id = NULL;
const char *child_id = NULL;
const char *right_val = NULL;
CRM_CHECK(child != NULL, return FALSE);
CRM_CHECK(update != NULL, return FALSE);
up_id = ID(update);
child_id = ID(child);
if(child_id == up_id || safe_str_eq(child_id, up_id)) {
can_delete = TRUE;
}
if(safe_str_neq(crm_element_name(update), crm_element_name(child))) {
can_delete = FALSE;
}
if(can_delete && delete_only) {
xml_prop_iter(update, prop_name, left_value,
right_val = crm_element_value(child, prop_name);
if(safe_str_neq(left_value, right_val)) {
can_delete = FALSE;
}
);
}
if(can_delete && parent != NULL) {
crm_log_xml_debug_4(child, "Delete match found...");
if(delete_only) {
cl_msg_remove_value(parent, child);
} else {
/* preserve the order */
cl_msg_replace_value(parent, child, update,
sizeof(struct ha_msg), FT_STRUCT);
}
child = NULL;
return TRUE;
} else if(can_delete) {
crm_log_xml_debug(child, "Cannot delete the search root");
can_delete = FALSE;
}
xml_child_iter(
child, child_of_child,
/* only delete the first one */
if(can_delete) {
break;
}
can_delete = replace_xml_child(child, child_of_child, update, delete_only);
);
return can_delete;
}
void
hash2nvpair(gpointer key, gpointer value, gpointer user_data)
{
const char *name = key;
const char *s_value = value;
crm_data_t *xml_node = user_data;
crm_data_t *xml_child = create_xml_node(xml_node, XML_CIB_TAG_NVPAIR);
crm_xml_add(xml_child, XML_ATTR_ID, name);
crm_xml_add(xml_child, XML_NVPAIR_ATTR_NAME, name);
crm_xml_add(xml_child, XML_NVPAIR_ATTR_VALUE, s_value);
crm_debug_3("dumped: name=%s value=%s", name, s_value);
}
void
hash2field(gpointer key, gpointer value, gpointer user_data)
{
const char *name = key;
const char *s_value = value;
crm_data_t *xml_node = user_data;
if(crm_element_value(xml_node, name) == NULL) {
crm_xml_add(xml_node, name, s_value);
crm_debug_3("dumped: %s=%s", name, s_value);
} else {
crm_debug_2("duplicate: %s=%s", name, s_value);
}
}
void
hash2metafield(gpointer key, gpointer value, gpointer user_data)
{
char *crm_name = NULL;
if(key == NULL || value == NULL) {
return;
}
crm_name = crm_concat(CRM_META, key, '_');
hash2field(crm_name, value, user_data);
crm_free(crm_name);
}
#if CRM_DEPRECATED_SINCE_2_0_3
GHashTable *
xml2list_202(crm_data_t *parent)
{
crm_data_t *nvpair_list = NULL;
GHashTable *nvpair_hash = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
CRM_CHECK(parent != NULL, return nvpair_hash);
nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE);
if(nvpair_list == NULL) {
crm_debug("No attributes in %s",
crm_element_name(parent));
crm_log_xml_debug_2(
parent,"No attributes for resource op");
}
xml_child_iter_filter(
nvpair_list, node_iter, XML_CIB_TAG_NVPAIR,
const char *key = crm_element_value(
node_iter, XML_NVPAIR_ATTR_NAME);
const char *value = crm_element_value(
node_iter, XML_NVPAIR_ATTR_VALUE);
crm_debug_2("Added %s=%s", key, value);
g_hash_table_insert(
nvpair_hash, crm_strdup(key), crm_strdup(value));
);
return nvpair_hash;
}
#endif
GHashTable *
xml2list(crm_data_t *parent)
{
crm_data_t *nvpair_list = NULL;
GHashTable *nvpair_hash = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
CRM_CHECK(parent != NULL, return nvpair_hash);
nvpair_list = find_xml_node(parent, XML_TAG_ATTRS, FALSE);
if(nvpair_list == NULL) {
crm_debug_2("No attributes in %s",
crm_element_name(parent));
crm_log_xml_debug_2(
parent,"No attributes for resource op");
}
crm_log_xml_debug_3(nvpair_list, "Unpacking");
xml_prop_iter(
nvpair_list, key, value,
crm_debug_4("Added %s=%s", key, value);
g_hash_table_insert(
nvpair_hash, crm_strdup(key), crm_strdup(value));
);
return nvpair_hash;
}
static void
assign_uuid(crm_data_t *xml_obj)
{
cl_uuid_t new_uuid;
char *new_uuid_s = NULL;
const char *tag_name = crm_element_name(xml_obj);
const char *tag_id = ID(xml_obj);
crm_malloc0(new_uuid_s, 38);
cl_uuid_generate(&new_uuid);
cl_uuid_unparse(&new_uuid, new_uuid_s);
crm_warn("Updating object from <%s id=%s/> to <%s id=%s/>",
tag_name, tag_id?tag_id:"__empty__", tag_name, new_uuid_s);
crm_xml_add(xml_obj, XML_ATTR_ID, new_uuid_s);
crm_log_xml_debug(xml_obj, "Updated object");
crm_free(new_uuid_s);
}
static gboolean
tag_needs_id(const char *tag_name)
{
int lpc = 0;
const char *allowed_list[] = {
XML_TAG_CIB,
XML_TAG_FRAGMENT,
XML_CIB_TAG_NODES,
XML_CIB_TAG_RESOURCES,
XML_CIB_TAG_CONSTRAINTS,
XML_CIB_TAG_STATUS,
XML_LRM_TAG_RESOURCES,
"configuration",
"crm_config",
"attributes",
"operations",
"diff",
"diff-added",
"diff-removed",
};
for(lpc = 0; lpc < DIMOF(allowed_list); lpc++) {
if(crm_str_eq(tag_name, allowed_list[lpc], TRUE)) {
/* this tag is never meant to have an ID */
return FALSE;
}
}
return TRUE;
}
static gboolean
non_unique_allowed(const char *tag_name)
{
int lpc = 0;
const char *non_unique[] = {
XML_LRM_TAG_RESOURCE,
XML_LRM_TAG_RSC_OP,
};
for(lpc = 0; lpc < DIMOF(non_unique); lpc++) {
if(safe_str_eq(tag_name, non_unique[lpc])) {
/* this tag can have a non-unique ID */
return TRUE;
}
}
return FALSE;
}
gboolean
do_id_check(crm_data_t *xml_obj, GHashTable *id_hash,
gboolean silent_add, gboolean silent_rename)
{
char *lookup_id = NULL;
gboolean modified = FALSE;
char *old_id = NULL;
const char *tag_id = NULL;
const char *tag_name = NULL;
const char *lookup_value = NULL;
gboolean created_hash = FALSE;
if(xml_obj == NULL) {
return FALSE;
} else if(id_hash == NULL) {
created_hash = TRUE;
id_hash = g_hash_table_new_full(
g_str_hash, g_str_equal,
g_hash_destroy_str, g_hash_destroy_str);
}
xml_child_iter(
xml_obj, xml_child,
if(do_id_check(xml_child, id_hash, silent_add, silent_rename)) {
modified = TRUE;
}
);
tag_id = ID(xml_obj);
tag_name = TYPE(xml_obj);
if(tag_needs_id(tag_name) == FALSE) {
crm_debug_5("%s does not need an ID", tag_name);
goto finish_id_check;
} else if(tag_id != NULL && non_unique_allowed(tag_name)){
crm_debug_5("%s does not need top be unique", tag_name);
goto finish_id_check;
}
lookup_id = NULL;
if(tag_id != NULL) {
lookup_id = crm_concat(tag_name, tag_id, '-');
lookup_value = g_hash_table_lookup(id_hash, lookup_id);
if(lookup_value == NULL) {
g_hash_table_insert(id_hash, lookup_id, crm_strdup(tag_id));
goto finish_id_check;
}
modified |= (!silent_rename);
} else {
modified |= (!silent_add);
}
if(tag_id != NULL) {
old_id = crm_strdup(tag_id);
}
crm_free(lookup_id);
assign_uuid(xml_obj);
tag_id = ID(xml_obj);
if(modified == FALSE) {
/* nothing to report */
} else if(old_id != NULL && safe_str_neq(tag_id, old_id)) {
crm_err("\"id\" collision detected... Multiple '%s' entries"
" with id=\"%s\", assigned id=\"%s\"",
tag_name, old_id, tag_id);
} else if(old_id == NULL && tag_id != NULL) {
crm_err("Detected <%s.../> object without an ID. Assigned: %s",
tag_name, tag_id);
}
crm_free(old_id);
finish_id_check:
if(created_hash) {
g_hash_table_destroy(id_hash);
}
return modified;
}
typedef struct name_value_s
{
const char *name;
const void *value;
} name_value_t;
static gint
sort_pairs(gconstpointer a, gconstpointer b)
{
const name_value_t *pair_a = a;
const name_value_t *pair_b = b;
if(a == NULL && b == NULL) {
return 0;
} else if(a == NULL) {
return 1;
} else if(b == NULL) {
return -1;
}
if(pair_a->name == NULL && pair_b->name == NULL) {
return 0;
} else if(pair_a->name == NULL) {
return 1;
} else if(pair_b->name == NULL) {
return -1;
}
return strcmp(pair_a->name, pair_b->name);
}
static void
dump_pair(gpointer data, gpointer user_data)
{
name_value_t *pair = data;
crm_data_t *parent = user_data;
crm_xml_add(parent, pair->name, pair->value);
}
static void
free_pair(gpointer data, gpointer user_data)
{
name_value_t *pair = data;
crm_free(pair);
}
static crm_data_t *
sorted_xml(const crm_data_t *input)
{
GListPtr sorted = NULL;
GListPtr unsorted = NULL;
name_value_t *pair = NULL;
crm_data_t *result = NULL;
const char *name = crm_element_name(input);
CRM_CHECK(input != NULL, return NULL);
name = crm_element_name(input);
CRM_CHECK(name != NULL, return NULL);
result = create_xml_node(NULL, name);
xml_prop_iter(input, p_name, p_value,
crm_malloc0(pair, sizeof(name_value_t));
pair->name = p_name;
pair->value = p_value;
unsorted = g_list_prepend(unsorted, pair);
pair = NULL;
);
sorted = g_list_sort(unsorted, sort_pairs);
g_list_foreach(sorted, dump_pair, result);
g_list_foreach(sorted, free_pair, NULL);
g_list_free(sorted);
return result;
}
/* "c048eae664dba840e1d2060f00299e9d" */
char *
calculate_xml_digest(crm_data_t *input, gboolean sort)
{
int i = 0;
int digest_len = 16;
char *digest = NULL;
unsigned char *raw_digest = NULL;
crm_data_t *sorted = NULL;
char *buffer = NULL;
size_t buffer_len = 0;
if(sort) {
sorted = sorted_xml(input);
} else {
sorted = copy_xml(input);
}
buffer = dump_xml_formatted(sorted);
buffer_len = strlen(buffer);
CRM_CHECK(buffer != NULL && buffer_len > 0,
free_xml(sorted); return NULL);
crm_malloc0(digest, (2 * digest_len + 1));
crm_malloc0(raw_digest, (digest_len + 1));
MD5((unsigned char *)buffer, buffer_len, raw_digest);
for(i = 0; i < digest_len; i++) {
sprintf(digest+(2*i), "%02x", raw_digest[i]);
}
crm_debug_2("Digest %s: %s\n", digest, buffer);
crm_log_xml(LOG_DEBUG_3, "digest:source", sorted);
crm_free(buffer);
crm_free(raw_digest);
free_xml(sorted);
return digest;
}
#if HAVE_LIBXML2
# include <libxml/parser.h>
# include <libxml/tree.h>
#endif
gboolean
validate_with_dtd(
crm_data_t *xml_blob, gboolean to_logs, const char *dtd_file)
{
gboolean valid = TRUE;
#if HAVE_LIBXML2
char *buffer = NULL;
xmlDocPtr doc = NULL;
xmlDtdPtr dtd = NULL;
xmlValidCtxtPtr cvp = NULL;
CRM_CHECK(xml_blob != NULL, return FALSE);
CRM_CHECK(dtd_file != NULL, return FALSE);
buffer = dump_xml_formatted(xml_blob);
CRM_CHECK(buffer != NULL, return FALSE);
doc = xmlParseMemory(buffer, strlen(buffer));
CRM_CHECK(doc != NULL, valid = FALSE; goto cleanup);
dtd = xmlParseDTD(NULL, (const xmlChar *)dtd_file);
CRM_CHECK(dtd != NULL, goto cleanup);
cvp = xmlNewValidCtxt();
CRM_CHECK(cvp != NULL, goto cleanup);
if(to_logs) {
cvp->userData = (void *) LOG_ERR;
cvp->error = (xmlValidityErrorFunc) cl_log;
cvp->warning = (xmlValidityWarningFunc) cl_log;
} else {
cvp->userData = (void *) stderr;
cvp->error = (xmlValidityErrorFunc) fprintf;
cvp->warning = (xmlValidityWarningFunc) fprintf;
}
if (!xmlValidateDtd(cvp, doc, dtd)) {
crm_err("CIB does not validate against %s", dtd_file);
crm_log_xml_debug(xml_blob, "invalid");
valid = FALSE;
}
cleanup:
xmlFreeValidCtxt(cvp);
xmlFreeDtd(dtd);
xmlFreeDoc(doc);
crm_free(buffer);
#endif
return valid;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Nov 23, 2:44 AM (9 m, 7 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1018061
Default Alt Text
(75 KB)
Attached To
Mode
rP Pacemaker
Attached
Detach File
Event Timeline
Log In to Comment