diff --git a/crm/admin/Makefile.am b/crm/admin/Makefile.am index 7ff89ca05d..3706ad8c86 100644 --- a/crm/admin/Makefile.am +++ b/crm/admin/Makefile.am @@ -1,83 +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@ XML_FLAGS = `xml2-config --cflags` XML_LIBS = `xml2-config --libs` # 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/crm/common/libcrmcommon.la \ $(top_builddir)/lib/crm/cib/libcib.la \ $(top_builddir)/lib/apphb/libapphb.la \ $(top_builddir)/lib/hbclient/libhbclient.la \ $(GLIBLIB) \ $(LIBRT) LIBRT = @LIBRT@ AM_CFLAGS = @CFLAGS@ \ $(CRM_DEBUG_FLAGS) ## libraries lib_LTLIBRARIES = ## binary progs -halib_PROGRAMS = crmadmin cibadmin ccm_tool +halib_PROGRAMS = crmadmin cibadmin ccm_tool crm_diff ## SOURCES #noinst_HEADERS = config.h control.h crmd.h noinst_HEADERS = crmadmin_SOURCES = crmadmin.c crmadmin_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' crmadmin_LDFLAGS = $(XML_LIBS) crmadmin_LDADD = $(COMMONLIBS) cibadmin_SOURCES = cibadmin.c cibadmin_CFLAGS = $(XML_FLAGS) -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' cibadmin_LDFLAGS = $(XML_LIBS) cibadmin_LDADD = $(COMMONLIBS) ccm_tool_SOURCES = ccm_epoche.c ccm_tool_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' ccm_tool_LDADD = $(COMMONLIBS) \ $(top_builddir)/membership/ccm/libccmclient.la +crm_diff_SOURCES = xml_diff.c +crm_diff_CFLAGS = -DHA_VARLIBDIR='"@HA_VARLIBDIR@"' +crm_diff_LDADD = $(COMMONLIBS) + clean-generic: rm -f *.log *.debug *.xml *~ install-exec-local: uninstall-local: diff --git a/crm/admin/xml_diff.c b/crm/admin/xml_diff.c new file mode 100644 index 0000000000..06425e3972 --- /dev/null +++ b/crm/admin/xml_diff.c @@ -0,0 +1,243 @@ +/* $Id: xml_diff.c,v 1.1 2005/06/13 11:37:38 andrew Exp $ */ + +/* + * 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.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 + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include /* someone complaining about _ha_msg_mod not being found */ +#include + +const char *crm_system_name = "diff"; +void usage(const char *cmd, int exit_status); + +#define OPTARGS "V?o:n:p:sc" + +int +main(int argc, char **argv) +{ + gboolean apply = TRUE; + gboolean use_stdin = FALSE; + gboolean as_cib = FALSE; + int option_index = 0; + int argerr = 0; + int flag; + crm_data_t *object_1 = NULL; + crm_data_t *object_2 = NULL; + crm_data_t *output = NULL; + const char *xml_file_1 = NULL; + const char *xml_file_2 = NULL; + + static struct option long_options[] = { + /* Top-level Options */ + {"original", 1, 0, 'o'}, + {"new", 1, 0, 'n'}, + {"patch", 1, 0, 'p'}, + {"stdin", 0, 0, 's'}, + {"cib", 0, 0, 'c'}, + {"verbose", 0, 0, 'V'}, + {"help", 0, 0, '?'}, + {0, 0, 0, 0} + }; + + cl_log_set_entity(crm_system_name); + cl_log_set_facility(LOG_USER); + set_crm_log_level(LOG_CRIT-1); + + if(argc < 2) { + usage(crm_system_name, LSB_EXIT_EINVAL); + } + + while (1) { + flag = getopt_long(argc, argv, OPTARGS, + long_options, &option_index); + if (flag == -1) + break; + + switch(flag) { + case 'o': + xml_file_1 = optarg; + apply = FALSE; + break; + case 'n': + xml_file_2 = optarg; + apply = FALSE; + break; + case 'p': + xml_file_2 = optarg; + apply = TRUE; + break; + case 's': + use_stdin = TRUE; + break; + case 'c': + as_cib = TRUE; + break; + case 'V': + cl_log_enable_stderr(TRUE); + alter_debug(DEBUG_INC); + break; + default: + printf("Argument code 0%o (%c)" + " is not (?yet?) supported\n", + flag, flag); + ++argerr; + break; + } + } + + if (optind < argc) { + printf("non-option ARGV-elements: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + } + + if (optind > argc) { + ++argerr; + } + + if (argerr) { + usage(crm_system_name, LSB_EXIT_GENERIC); + } + + if(use_stdin) { + fprintf(stderr, "Input first XML fragment:"); + object_1 = stdin2xml(); + + } else if(xml_file_1 != NULL) { + FILE *xml_strm = fopen(xml_file_1, "r"); + if(xml_strm != NULL) { + crm_debug("Reading: %s", xml_file_1); + object_1 = file2xml(xml_strm); + } else { + cl_perror("File not found: %s", xml_file_1); + } + } + + if(use_stdin) { + fprintf(stderr, "Input second XML fragment:"); + object_2 = stdin2xml(); + + } else if(xml_file_1 != NULL) { + FILE *xml_strm = fopen(xml_file_2, "r"); + if(xml_strm != NULL) { + crm_debug("Reading: %s", xml_file_2); + object_2 = file2xml(xml_strm); + } else { + cl_perror("File not found: %s", xml_file_2); + } + + } + + CRM_ASSERT(object_1 != NULL); + CRM_ASSERT(object_2 != NULL); + + if(as_cib == FALSE) { + if(apply) { + apply_xml_diff(object_1, object_2, &output); + } else { + output = diff_xml_object(object_1, object_2, FALSE); + } + } else { + if(apply) { + apply_cib_diff(object_1, object_2, &output); + } else { + output = diff_cib_object(object_1, object_2, FALSE); + } + } + + + if(output != NULL) { + char *buffer = dump_xml_formatted(output); + fprintf(stdout, "%s", crm_str(buffer)); + crm_free(buffer); + } + + return 0; +} + + +void +usage(const char *cmd, int exit_status) +{ + FILE *stream; + + stream = exit_status != 0 ? stderr : stdout; + + fprintf(stream, "usage: %s [-?Vio] command\n" + "\twhere necessary, XML data will be expected using -X" + " or on STDIN if -X isnt specified\n", cmd); + + fprintf(stream, "Options\n"); + fprintf(stream, "\t--%s (-%c) \tid of the object being operated on\n", + XML_ATTR_ID, 'i'); + fprintf(stream, "\t--%s (-%c) \tobject type being operated on\n", + "obj_type", 'o'); + fprintf(stream, "\t--%s (-%c)\tturn on debug info." + " additional instance increase verbosity\n", "verbose", 'V'); + fprintf(stream, "\t--%s (-%c)\tthis help message\n", "help", '?'); + fprintf(stream, "\nCommands\n"); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ERASE, 'E'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_QUERY, 'Q'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_CREATE, 'C'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_REPLACE,'R'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_UPDATE, 'U'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_DELETE, 'D'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_BUMP, 'B'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_ISMASTER,'M'); + fprintf(stream, "\t--%s (-%c)\t\n", CIB_OP_SYNC, 'S'); + fprintf(stream, "\nXML data\n"); + fprintf(stream, "\t--%s (-%c) \t\n", F_CRM_DATA, 'X'); + fprintf(stream, "\nAdvanced Options\n"); + fprintf(stream, "\t--%s (-%c)\tsend command to specified host." + " Applies to %s and %s commands only\n", "host", 'h', + CIB_OP_QUERY, CIB_OP_SYNC); + fprintf(stream, "\t--%s (-%c)\tcommand takes effect locally" + " on the specified host\n", "local", 'l'); + fprintf(stream, "\t--%s (-%c)\tcommand will not be broadcast even if" + " it altered the CIB\n", "no-bcast", 'b'); + fprintf(stream, "\t--%s (-%c)\twait for call to complete before" + " returning\n", "sync-call", 's'); + + fflush(stream); + + exit(exit_status); +}