osaf/tools/safimm/immcfg/imm_cfg.c | 31 +++- osaf/tools/safimm/immcfg/imm_import.cc | 196 ++++++++++++++++++++++++++++- osaf/tools/safimm/immdump/imm_dumper.cc | 170 +++++++++++++++++++++++- osaf/tools/safimm/immdump/imm_dumper.hh | 2 + osaf/tools/safimm/immdump/imm_xmlw_dump.cc | 13 +- osaf/tools/safimm/immlist/Makefile.am | 4 + osaf/tools/safimm/immlist/imm_list.c | 191 ++++++++++++++++++++++++++++- osaf/tools/safimm/immload/imm_loader.cc | 164 ++++++++++++++++++++++++- 8 files changed, 749 insertions(+), 22 deletions(-)
For forwards compatibility, OpenSAF schema, where unknown attribute flags are defined, must be provided to IMM tools (immcfg, immlist, immfind) using -X flag. If immload finds unknown attribute flag, immload will try to find the attribute flag in the schema defined in the top element of the loading IMM XML file. diff --git a/osaf/tools/safimm/immcfg/imm_cfg.c b/osaf/tools/safimm/immcfg/imm_cfg.c --- a/osaf/tools/safimm/immcfg/imm_cfg.c +++ b/osaf/tools/safimm/immcfg/imm_cfg.c @@ -56,7 +56,7 @@ typedef enum { #define VERBOSE_INFO(format, args...) if (verbose) { fprintf(stderr, format, ##args); } // The interface function which implements the -f opton (imm_import.cc) -int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe); +int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, const char *xsdPath); const SaImmCcbFlagsT defCcbFlags = SA_IMM_CCB_REGISTERED_OI | SA_IMM_CCB_ALLOW_NULL_OI; @@ -86,6 +86,7 @@ static void usage(const char *progname) printf("\t--ignore-duplicates (only valid with -f/--file option, default)\n"); printf("\t--delete-class <classname> [classname2]... \n"); printf("\t-u, --unsafe\n"); + printf("\t-X, --xsd <path_to_schema.xsd>\n"); printf("\nEXAMPLE\n"); printf("\timmcfg -a saAmfNodeSuFailoverMax=7 safAmfNode=Node01,safAmfCluster=1\n"); @@ -102,6 +103,10 @@ static void usage(const char *progname) printf("\t\tremove a value from an attribute\n"); printf("\timmcfg -u .....\n"); printf("\t\tThe CCBs generated by immcfg will have SA_IMM_CCB_REGISTERED_OI set to false, allowing ccb commit when OIs are missing\n"); + printf("\timmcfg -X /etc/opensaf/schema.xsd -f imm.xml\n"); + printf("\t\timmcfg will load unsupported attribute flags in the current OpenSAF version from /etc/opensaf/schema.xsd, and use them to successfully import imm.xml"); + printf("\timmcfg -X /etc/opensaf -f imm.xml\n"); + printf("\t\timmcfg will load unsupported attribute flags in the current OpenSAF version from the schema specified in imm.xml which is stored in /etc/opensaf, and use loaded flags to successfully import imm.xml"); } /* signal handler for SIGALRM */ @@ -682,6 +687,7 @@ int main(int argc, char *argv[]) {"timeout", required_argument, NULL, 't'}, {"verbose", no_argument, NULL, 'v'}, {"unsafe", no_argument, NULL, 'u'}, + {"xsd", required_argument, NULL, 'X'}, {0, 0, 0, 0} }; SaAisErrorT error; @@ -703,9 +709,11 @@ int main(int argc, char *argv[]) int i; unsigned long timeoutVal = 60; + char *xsdPath = NULL; + while (1) { int option_index = 0; - c = getopt_long(argc, argv, "a:c:f:t:dhmvu", long_options, &option_index); + c = getopt_long(argc, argv, "a:c:f:t:dhmvuX:", long_options, &option_index); if (c == -1) /* have all command-line options have been parsed? */ break; @@ -751,6 +759,13 @@ int main(int argc, char *argv[]) op = verify_setoption(op, MODIFY_OBJECT); break; } + case 'X': + if(xsdPath) { + fprintf(stderr, "XSD path is already set\n"); + exit(EXIT_FAILURE); + } + xsdPath = strdup(optarg); + break; default: fprintf(stderr, "Try '%s --help' for more information\n", argv[0]); exit(EXIT_FAILURE); @@ -767,7 +782,7 @@ int main(int argc, char *argv[]) if (op == LOAD_IMMFILE) { VERBOSE_INFO("importImmXML(xmlFilename=%s, verbose=%d)\n", xmlFilename, verbose); - rc = importImmXML(xmlFilename, adminOwnerName, verbose, ccb_safe); + rc = importImmXML(xmlFilename, adminOwnerName, verbose, ccb_safe, xsdPath); exit(rc); } @@ -854,10 +869,14 @@ int main(int argc, char *argv[]) done_om_finalize: error = immutil_saImmOmFinalize(immHandle); if (SA_AIS_OK != error) { - fprintf(stderr, "error - saImmOmFinalize FAILED: %s\n", saf_error(error)); - rc = EXIT_FAILURE; - } + fprintf(stderr, "error - saImmOmFinalize FAILED: %s\n", saf_error(error)); + rc = EXIT_FAILURE; + } + if(xsdPath) { + free(xsdPath); + xsdPath = NULL; + } exit(rc); } diff --git a/osaf/tools/safimm/immcfg/imm_import.cc b/osaf/tools/safimm/immcfg/imm_import.cc --- a/osaf/tools/safimm/immcfg/imm_import.cc +++ b/osaf/tools/safimm/immcfg/imm_import.cc @@ -21,6 +21,8 @@ #include <set> #include <string> #include <libxml/parser.h> +#include <libxml/tree.h> +#include <libxml/xpath.h> #include <string.h> #include <stdio.h> #include <stdlib.h> @@ -28,6 +30,8 @@ #include <assert.h> #include <syslog.h> #include <configmake.h> +#include <sys/stat.h> +#include <errno.h> #include <saAis.h> #include <saImmOm.h> @@ -68,7 +72,7 @@ static char base64_dec_table[] = { extern "C" { - int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe); + int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, const char *xsdPath); } extern ImmutilErrorFnT immutilError; @@ -141,6 +145,20 @@ typedef struct ParserStateStruct { SaImmHandleT ccbHandle; } ParserState; +bool isXsdLoaded = false; +static const char *imm_xsd_file; +typedef std::map<std::string, SaImmAttrFlagsT> AttrFlagMap; +AttrFlagMap attrFlagMap; + +static SaImmAttrFlagsT attrFlagMask = (SA_IMM_ATTR_RUNTIME + | SA_IMM_ATTR_CONFIG + | SA_IMM_ATTR_MULTI_VALUE + | SA_IMM_ATTR_WRITABLE + | SA_IMM_ATTR_INITIALIZED + | SA_IMM_ATTR_PERSISTENT + | SA_IMM_ATTR_CACHED + | SA_IMM_ATTR_NOTIFY + | SA_IMM_ATTR_NO_DUPLICATES); /* Prototypes */ @@ -1001,6 +1019,160 @@ static inline bool isBase64Encoded(const return isB64; } +static inline char *getAttrValue(xmlAttributePtr attr) { + if(!attr || !attr->children) { + return NULL; + } + + return (char *)attr->children->content; +} + +static bool loadXsd(const xmlChar** attrs) { + if(!imm_xsd_file) { + return true; + } + + // Check if schema path exist + struct stat st; + if(stat(imm_xsd_file, &st)) { + if(errno == ENOENT) { + LOG_ER("%s does not exist", imm_xsd_file); + } else { + LOG_ER("stat of %s return error: %d", imm_xsd_file, errno); + } + + return false; + } + // It should be a file or a directory + if(!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) { + LOG_ER("%s is not a file or directory", imm_xsd_file); + return false; + } + + std::string xsdFile = imm_xsd_file; + if(S_ISDIR(st.st_mode)) { + // Schema path is a directory, so we shall add a schema file from XML file + if(xsdFile.at(xsdFile.size() - 1) != '/') { + xsdFile.append("/"); + } + char *xsd = (char *)getAttributeValue(attrs, (xmlChar *)"noNamespaceSchemaLocation"); + if(!xsd) { + // try with a namespace + xsd = (char *)getAttributeValue(attrs, (xmlChar *)"xsi:noNamespaceSchemaLocation"); + if(!xsd) { + LOG_ER("Schema is not defined in XML file"); + return false; + } + } + xsdFile.append(xsd); + + // Check if schema file exists and that it's a file + if(stat(xsdFile.c_str(), &st)) { + if(errno == ENOENT) { + LOG_ER("XSD file %s does not exist", imm_xsd_file); + } else { + LOG_ER("Stat of XSD file %s return error: %d", imm_xsd_file, errno); + } + + return false; + } + if(!S_ISREG(st.st_mode)) { + LOG_ER("Schema %s is not a file", xsdFile.c_str()); + return false; + } + } + + xmlNodePtr xsdDocRoot; + xmlDocPtr xsdDoc = xmlParseFile(xsdFile.c_str()); + if(!xsdDoc) { + return false; + } + + bool rc = true; + xmlXPathContextPtr ctx = xmlXPathNewContext(xsdDoc); + if(!ctx) { + rc = false; + goto freedoc; + } + + // Add namespace of the first element + xsdDocRoot = xmlDocGetRootElement(xsdDoc); + if(xsdDocRoot->ns) { + ctx->namespaces = (xmlNsPtr *)malloc(sizeof(xmlNsPtr)); + ctx->namespaces[0] = xsdDocRoot->ns; + ctx->nsNr = 1; + } + + xmlXPathObjectPtr xpathObj; + xpathObj = xmlXPathEval((const xmlChar*)"/xs:schema/xs:simpleType[@name=\"attr-flags\"]/xs:restriction/xs:enumeration", ctx); + if(!xpathObj || !xpathObj->nodesetval) { + rc = false; + goto freectx; + } + + xmlElementPtr element; + xmlAttributePtr attr; + char *id; + char *value; + int size; + + size = xpathObj->nodesetval->nodeNr; + for(int i=0; i<size; i++) { + id = NULL; + value = NULL; + element = (xmlElementPtr)xpathObj->nodesetval->nodeTab[i]; + attr = element->attributes; + while(attr) { + if(!strcmp((char *)attr->name, "ID")) { + id = getAttrValue(attr); + } else if(!strcmp((char *)attr->name, "value")) { + value = getAttrValue(attr); + } + + if(id && value) { + break; + } + + attr = (xmlAttributePtr)attr->next; + } + + if(value) { + SaImmAttrFlagsT attrFlag = 0; + + if(id) { + char *end; + if(!strncmp(id, "0x", 2)) { + attrFlag = strtoull(id, &end, 16); + } else { + attrFlag = strtoull(id, &end, 10); + } + + if(*end) { + LOG_WA("INVALID ID(%s) FOR FLAG %s. Attribute flag is set to 0", id, value); + attrFlag = 0; + } + } + + if((attrFlag & ~attrFlagMask) || attrFlag == 0) { + attrFlagMap[value] = attrFlag; + } + } + } + + isXsdLoaded = true; + + xmlXPathFreeObject(xpathObj); +freectx: + if(ctx->nsNr) { + free(ctx->namespaces); + } + xmlXPathFreeContext(ctx); +freedoc: + xmlFreeDoc(xsdDoc); + + return rc; +} + /** * This is the handler for start tags */ @@ -1125,6 +1297,12 @@ static void startElementHandler(void* us /* <imm:IMM-contents> */ } else if (strcmp((const char*)name, "imm:IMM-contents") == 0) { state->state[state->depth] = IMM_CONTENTS; + if(imm_xsd_file) { + if(!loadXsd(attrs)) { + LOG_ER("Failed to load XML schema", name); + exit(1); + } + } } else { LOG_ER("UNKNOWN TAG! (%s)", name); exit(1); @@ -1568,7 +1746,15 @@ static SaImmAttrFlagsT charsToFlagsHelpe return SA_IMM_ATTR_NOTIFY; } - LOG_ER("UNKNOWN FLAGS, %s", str); + std::string flag((char *)str, len); + if(isXsdLoaded) { + AttrFlagMap::iterator it = attrFlagMap.find(flag); + if(it != attrFlagMap.end()) { + return it->second; + } + } + + LOG_ER("UNKNOWN FLAGS, %s", flag.c_str()); exit(1); } @@ -2036,7 +2222,7 @@ int loadImmXML(std::string xmlfile) // C and c++ caller wrapper // The objective is to keep the code copied from imm_load.cc as close to original as possible // to ease a future refactoring towards common codebase -int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe) +int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int ccb_safe, const char *xsdPath) { std::string xmlfile(xmlfileC); imm_import_adminOwnerName = adminOwnerName; @@ -2044,6 +2230,10 @@ int importImmXML(char* xmlfileC, char* a imm_import_ccb_safe = ccb_safe; LOG_IN("file: %s adminOwner: %s", xmlfileC, adminOwnerName); + imm_xsd_file = xsdPath; + isXsdLoaded = false; + attrFlagMap.clear(); + // assign own immutil errorhandler (no call to abort()) immutilError = imm_importImmutilError; diff --git a/osaf/tools/safimm/immdump/imm_dumper.cc b/osaf/tools/safimm/immdump/imm_dumper.cc --- a/osaf/tools/safimm/immdump/imm_dumper.cc +++ b/osaf/tools/safimm/immdump/imm_dumper.cc @@ -24,16 +24,31 @@ #include <limits.h> #include <libxml/parser.h> #include <libxml/xmlmemory.h> +#include <libxml/xpath.h> #include <getopt.h> #include <assert.h> #include <libgen.h> #include <unistd.h> +#include <sys/stat.h> +#include <errno.h> + #define XML_VERSION "1.0" /* Prototypes */ static std::map<std::string, std::string> cacheRDNs(SaImmHandleT); +AttrFlagMap attrFlagMap; + +static SaImmAttrFlagsT attrFlagMask = (SA_IMM_ATTR_RUNTIME + | SA_IMM_ATTR_CONFIG + | SA_IMM_ATTR_MULTI_VALUE + | SA_IMM_ATTR_WRITABLE + | SA_IMM_ATTR_INITIALIZED + | SA_IMM_ATTR_PERSISTENT + | SA_IMM_ATTR_CACHED + | SA_IMM_ATTR_NO_DUPLICATES); + static void usage(const char *progname) { printf("\nNAME\n"); @@ -54,6 +69,9 @@ static void usage(const char *progname) printf("\t-p, --pbe {<file name>}\n"); printf("\t\tInstead of xml file, generate/populate persistent back-end database/file\n"); + printf("\t-X, --xsd {<file name>}\n"); + printf("\t\tLoad missing data from IMM schema\n\n"); + printf("\nEXAMPLE\n"); printf("\timmdump /tmp/imm.xml\n"); } @@ -84,6 +102,122 @@ static const SaImmCallbacksT callbacks = saImmOmAdminOperationInvokeCallback }; +static inline char *getAttrValue(xmlAttributePtr attr) { + if(!attr || !attr->children) { + return NULL; + } + + return (char *)attr->children->content; +} + +static bool loadXsd(const char *xsdFile) { + struct stat st; + if(stat(xsdFile, &st)) { + if(errno == ENOENT) { + LOG_ER("%s does not exist", xsdFile); + } else { + LOG_ER("stat of %s return error: %d", xsdFile, errno); + } + + return false; + } + // It should be a file or a directory + if(!S_ISREG(st.st_mode)) { + LOG_ER("%s is not a file", xsdFile); + return false; + } + + xmlNodePtr xsdDocRoot; + xmlDocPtr xsdDoc = xmlParseFile(xsdFile); + if(!xsdDoc) { + return false; + } + + bool rc = true; + xmlXPathContextPtr ctx = xmlXPathNewContext(xsdDoc); + if(!ctx) { + rc = false; + goto freedoc; + } + + // Add namespace of the first element + xsdDocRoot = xmlDocGetRootElement(xsdDoc); + if(xsdDocRoot->ns) { + ctx->namespaces = (xmlNsPtr *)malloc(sizeof(xmlNsPtr)); + ctx->namespaces[0] = xsdDocRoot->ns; + ctx->nsNr = 1; + } + + xmlXPathObjectPtr xpathObj; + xpathObj = xmlXPathEval((const xmlChar*)"/xs:schema/xs:simpleType[@name=\"attr-flags\"]/xs:restriction/xs:enumeration", ctx); + if(!xpathObj || !xpathObj->nodesetval) { + rc = false; + goto freectx; + } + + xmlElementPtr element; + xmlAttributePtr attr; + char *id; + char *value; + int size; + + size = xpathObj->nodesetval->nodeNr; + for(int i=0; i<size; i++) { + id = NULL; + value = NULL; + element = (xmlElementPtr)xpathObj->nodesetval->nodeTab[i]; + attr = element->attributes; + while(attr) { + if(!strcmp((char *)attr->name, "ID")) { + id = getAttrValue(attr); + } else if(!strcmp((char *)attr->name, "value")) { + value = getAttrValue(attr); + } + + if(id && value) { + break; + } + + attr = (xmlAttributePtr)attr->next; + } + + if(id && value) { + SaImmAttrFlagsT attrFlag; + char *end; + if(!strncmp(id, "0x", 2)) { + attrFlag = strtoull(id, &end, 16); + } else { + attrFlag = strtoull(id, &end, 10); + } + + if(*end) { + LOG_WA("INVALID ID(%s) FOR FLAG %s.", id, value); + attrFlagMap.clear(); + rc = false; + goto freexpath; + } else if(((attrFlag & ~attrFlagMask) || (attrFlag == 0)) && + strcmp(value, "SA_RUNTIME") && strcmp(value, "SA_CONFIG") && + strcmp(value, "SA_MULTI_VALUE") && strcmp(value, "SA_WRITABLE") && + strcmp(value, "SA_INITIALIZED") && strcmp(value, "SA_PERSISTENT") && + strcmp(value, "SA_CACHED") && strcmp(value, "SA_NOTIFY") && + strcmp(value, "SA_NO_DUPLICATES") && strcmp(value, "SA_NO_DANGLING")) { + attrFlagMap[value] = attrFlag; + } + } + } + +freexpath: + xmlXPathFreeObject(xpathObj); +freectx: + if(ctx->nsNr) { + free(ctx->namespaces); + } + xmlXPathFreeContext(ctx); +freedoc: + xmlFreeDoc(xsdDoc); + + return rc; +} /* Functions */ int main(int argc, char* argv[]) @@ -95,6 +229,7 @@ int main(int argc, char* argv[]) {"pbe", required_argument, 0, 'p'}, {"recover", no_argument, 0, 'r'}, {"xmlwriter", no_argument, 0, 'x'}, + {"xsd", required_argument, 0, 'X'}, {0, 0, 0, 0} }; SaImmHandleT immHandle; @@ -129,6 +264,8 @@ int main(int argc, char* argv[]) const char* trace_label = dump_trace_label; ClassMap classIdMap; unsigned int objCount=0; + std::string xsd; + std::string schema = "SAI-AIS-IMM-XSD-A.02.12.xsd"; unsigned int retryInterval = 1000000; /* 1 sec */ unsigned int maxTries = 70; /* 70 times == max 70 secs */ @@ -151,12 +288,12 @@ int main(int argc, char* argv[]) if ((argc < 2) || (argc > 5)) { printf("Usage: %s <xmldumpfile>\n", argv[0]); - usage(argv[0]); + usage(argv[0]); exit(1); } while (1) { - if ((c = getopt_long(argc, argv, "hdrp:x:y:", long_options, NULL)) == -1) + if ((c = getopt_long(argc, argv, "hdrp:x:y:X:", long_options, NULL)) == -1) break; switch (c) { @@ -171,22 +308,26 @@ int main(int argc, char* argv[]) break; case 'p': - if(!pbeRecoverFile) { - pbeDumpCase = true; - } + if(!pbeRecoverFile) { + pbeDumpCase = true; + } - filename.append(optarg); + filename.append(optarg); break; case 'r': - pbeDumpCase = false; - pbeRecoverFile = true; + pbeDumpCase = false; + pbeRecoverFile = true; break; case 'x': filename.append(optarg); break; + case 'X': + xsd = optarg; + break; + default: fprintf(stderr, "Try '%s --help' for more information\n", argv[0]); @@ -196,7 +337,7 @@ int main(int argc, char* argv[]) } if(filename.empty()) { - filename.append(argv[1]); + filename.append(argv[optind]); } version.releaseCode = RELEASE_CODE; @@ -217,6 +358,15 @@ int main(int argc, char* argv[]) exit(1); } + if(xsd.size() > 0) { + if(!loadXsd(xsd.c_str())) { + std::cerr << "Failed to load schema - exiting\n"; + exit(1); + } + + schema = basename((char *)xsd.c_str()); + } + if(pbeDaemonCase && !pbeDumpCase && pbeRecoverFile) { /* This is the re-attachement case. The PBE has crashed, @@ -378,7 +528,7 @@ int main(int argc, char* argv[]) if(xmlTextWriterWriteAttributeNS(writer, (xmlChar*)"xsi",(xmlChar *)"noNamespaceSchemaLocation", NULL, - (xmlChar*)"SAI-AIS-IMM-XSD-A.01.02.xsd") < 0) { + (xmlChar*)schema.c_str()) < 0) { std::cout <<"Error at xmlTextWriterWriteAttribute (attribute 2)" << std::endl; exit(1); } diff --git a/osaf/tools/safimm/immdump/imm_dumper.hh b/osaf/tools/safimm/immdump/imm_dumper.hh --- a/osaf/tools/safimm/immdump/imm_dumper.hh +++ b/osaf/tools/safimm/immdump/imm_dumper.hh @@ -106,6 +106,8 @@ SaAisErrorT getCcbOutcomeFromPbe(void* d void discardPbeFile(std::string filename); void fsyncPbeJournalFile(); +typedef std::map<std::string, SaImmAttrFlagsT> AttrFlagMap; + /* XML-Writer related functions */ void dumpClassesXMLw(SaImmHandleT, xmlTextWriterPtr); diff --git a/osaf/tools/safimm/immdump/imm_xmlw_dump.cc b/osaf/tools/safimm/immdump/imm_xmlw_dump.cc --- a/osaf/tools/safimm/immdump/imm_xmlw_dump.cc +++ b/osaf/tools/safimm/immdump/imm_xmlw_dump.cc @@ -23,6 +23,7 @@ #include <osaf_unicode.h> +extern AttrFlagMap attrFlagMap; /* Functions */ @@ -490,7 +491,17 @@ void flagsToXMLw(SaImmAttrDefinitionT_2* exit(1); } } - + + AttrFlagMap::iterator it; + for(it = attrFlagMap.begin(); it != attrFlagMap.end(); ++it) { + if(flags & it->second) { + if(xmlTextWriterWriteElement(writer, (xmlChar*) "flag", + (xmlChar*) it->first.c_str()) < 0 ) { + std::cout << "Error at xmlTextWriterWriteElement (flag - " << it->first << ")" << std::endl; + exit(1); + } + } + } } void typeToXMLw(SaImmAttrDefinitionT_2* p, xmlTextWriterPtr writer) diff --git a/osaf/tools/safimm/immlist/Makefile.am b/osaf/tools/safimm/immlist/Makefile.am --- a/osaf/tools/safimm/immlist/Makefile.am +++ b/osaf/tools/safimm/immlist/Makefile.am @@ -20,6 +20,8 @@ MAINTAINERCLEANFILES = Makefile.in bin_PROGRAMS = immlist +immlist_CFLAGS = $(AM_CFLAGS) @XML2_CFLAGS@ + immlist_CPPFLAGS = \ $(AM_CPPFLAGS) \ -I$(top_srcdir)/osaf/tools/safimm/include \ @@ -30,6 +32,8 @@ immlist_SOURCES = \ $(top_srcdir)/osaf/tools/safimm/src/saf_error.c \ imm_list.c +immlist_LDFLAGS = @XML2_LIBS@ + immlist_LDADD = \ $(top_builddir)/osaf/libs/core/libopensaf_core.la \ $(top_builddir)/osaf/libs/saf/libSaImm/libSaImmOm.la \ diff --git a/osaf/tools/safimm/immlist/imm_list.c b/osaf/tools/safimm/immlist/imm_list.c --- a/osaf/tools/safimm/immlist/imm_list.c +++ b/osaf/tools/safimm/immlist/imm_list.c @@ -36,6 +36,10 @@ #include <libgen.h> #include <time.h> #include <signal.h> +#include <sys/stat.h> +#include <libxml/parser.h> +#include <libxml/xmlmemory.h> +#include <libxml/xpath.h> #include <saAis.h> #include <saImmOm.h> @@ -55,6 +59,23 @@ static SaVersionT immVersion = { 'A', 2, 11 }; extern struct ImmutilWrapperProfile immutilWrapperProfile; +typedef struct AttrFlagList { + char *name; + SaImmAttrFlagsT value; + struct AttrFlagList *next; +} AttrFlagList; +AttrFlagList *attrFlagList = NULL; + +static SaImmAttrFlagsT attrFlagMask = (SA_IMM_ATTR_RUNTIME + | SA_IMM_ATTR_CONFIG + | SA_IMM_ATTR_MULTI_VALUE + | SA_IMM_ATTR_WRITABLE + | SA_IMM_ATTR_INITIALIZED + | SA_IMM_ATTR_PERSISTENT + | SA_IMM_ATTR_CACHED + | SA_IMM_ATTR_NOTIFY + | SA_IMM_ATTR_NO_DUPLICATES); + /* signal handler for SIGALRM */ void sigalarmh(int sig) { @@ -81,6 +102,7 @@ static void usage(const char *progname) printf("\t-p, --pretty-print=<yes|no> - select pretty print, default yes\n"); printf("\t-t, --timeout <sec>\n"); printf("\t\tutility timeout in seconds\n"); + printf("\t-X, --xsd <schema.xsd>\n"); printf("\nEXAMPLE\n"); printf("\timmlist -a saAmfApplicationAdminState safApp=OpenSAF\n"); @@ -353,6 +375,14 @@ static void display_class_definition(con printf(", NO_DUPLICATES"); } + AttrFlagList *attrFlag = attrFlagList; + while(attrFlag) { + if(attrFlag->value & attrDefinition->attrFlags) { + printf(", %s", attrFlag->name); + } + attrFlag = attrFlag->next; + } + printf("}\n"); } @@ -411,6 +441,138 @@ static void display_object(const char *n } } +static inline char *getAttrValue(xmlAttributePtr attr) { + if(!attr || !attr->children) { + return NULL; + } + + return (char *)attr->children->content; +} + +static int loadXsd(const char *xsdFile) { + struct stat st; + if(stat(xsdFile, &st)) { + if(errno == ENOENT) { + fprintf(stderr, "%s does not exist", xsdFile); + } else { + fprintf(stderr, "stat of %s return error: %d", xsdFile, errno); + } + + return 0; + } + // It should be a file or a directory + if(!S_ISREG(st.st_mode)) { + fprintf(stderr, "%s is not a file", xsdFile); + return 0; + } + + xmlNodePtr xsdDocRoot; + xmlDocPtr xsdDoc = xmlParseFile(xsdFile); + if(!xsdDoc) { + return 0; + } + + int rc = 1; + xmlXPathContextPtr ctx = xmlXPathNewContext(xsdDoc); + if(!ctx) { + rc = 0; + goto freedoc; + } + + // Add namespace of the first element + xsdDocRoot = xmlDocGetRootElement(xsdDoc); + if(xsdDocRoot->ns) { + ctx->namespaces = (xmlNsPtr *)malloc(sizeof(xmlNsPtr)); + ctx->namespaces[0] = xsdDocRoot->ns; + ctx->nsNr = 1; + } + + xmlXPathObjectPtr xpathObj; + xpathObj = xmlXPathEval((const xmlChar*)"/xs:schema/xs:simpleType[@name=\"attr-flags\"]/xs:restriction/xs:enumeration", ctx); + if(!xpathObj || !xpathObj->nodesetval) { + rc = 0; + goto freectx; + } + + xmlElementPtr element; + xmlAttributePtr attr; + char *id; + char *value; + int size; + int i; + + size = xpathObj->nodesetval->nodeNr; + for(i=0; i<size; i++) { + id = NULL; + value = NULL; + element = (xmlElementPtr)xpathObj->nodesetval->nodeTab[i]; + attr = element->attributes; + while(attr) { + if(!strcmp((char *)attr->name, "ID")) { + id = getAttrValue(attr); + } else if(!strcmp((char *)attr->name, "value")) { + value = getAttrValue(attr); + } + + if(id && value) { + break; + } + + attr = (xmlAttributePtr)attr->next; + } + + if(id && value) { + AttrFlagList *flag; + SaImmAttrFlagsT attrFlag; + char *end; + if(!strncmp(id, "0x", 2)) { + attrFlag = strtoull(id, &end, 16); + } else { + attrFlag = strtoull(id, &end, 10); + } + + if(*end) { + fprintf(stdout, "INVALID ID(%s) FOR FLAG %s.", id, value); + + AttrFlagList *tmp; + flag = attrFlagList; + while(flag) { + tmp = flag->next; + free(flag->name); + free(flag); + flag = tmp; + } + attrFlagList = NULL; + rc = 0; + goto freexpath; + } else if(((attrFlag & ~attrFlagMask) || (attrFlag == 0)) && + strcmp(value, "SA_RUNTIME") && strcmp(value, "SA_CONFIG") && + strcmp(value, "SA_MULTI_VALUE") && strcmp(value, "SA_WRITABLE") && + strcmp(value, "SA_INITIALIZED") && strcmp(value, "SA_PERSISTENT") && + strcmp(value, "SA_CACHED") && strcmp(value, "SA_NOTIFY") && + strcmp(value, "SA_NO_DUPLICATES") && strcmp(value, "SA_NO_DANGLING")) { + flag = (AttrFlagList *)malloc(sizeof(AttrFlagList)); + flag->name = strdup(value); + flag->value = attrFlag; + flag->next = attrFlagList; + attrFlagList = flag; + } + } + } + +freexpath: + xmlXPathFreeObject(xpathObj); +freectx: + if(ctx->nsNr) { + free(ctx->namespaces); + } + xmlXPathFreeContext(ctx); +freedoc: + xmlFreeDoc(xsdDoc); + + return rc; +} + int main(int argc, char *argv[]) { int c; @@ -420,6 +582,7 @@ int main(int argc, char *argv[]) {"timeout", required_argument, 0, 't'}, {"help", no_argument, 0, 'h'}, {"pretty-print", required_argument, 0, 'p'}, + {"xsd", required_argument, 0, 'X'}, {0, 0, 0, 0} }; SaAisErrorT error; @@ -431,9 +594,10 @@ int main(int argc, char *argv[]) int class_desc_print = 0; int rc = EXIT_SUCCESS; unsigned long timeoutVal = 60; + char *xsd = NULL; while (1) { - c = getopt_long(argc, argv, "a:p:t:ch", long_options, NULL); + c = getopt_long(argc, argv, "a:p:t:cX:h", long_options, NULL); if (c == -1) /* have all command-line options have been parsed? */ break; @@ -459,6 +623,13 @@ int main(int argc, char *argv[]) if (!strcasecmp(optarg, "no")) pretty_print = 0; break; + case 'X': + if(xsd) { + fprintf(stderr, "Cannot set more then one schema\n"); + exit(EXIT_FAILURE); + } + xsd = strdup(optarg); + break; default: fprintf(stderr, "Try '%s --help' for more information\n", argv[0]); exit(EXIT_FAILURE); @@ -487,6 +658,13 @@ int main(int argc, char *argv[]) goto done; } + if(xsd) { + if(!loadXsd(xsd)) { + rc = EXIT_FAILURE; + goto done; + } + } + if (class_desc_print) { while (optind < argc) { display_class_definition(argv[optind], immHandle); @@ -515,6 +693,17 @@ int main(int argc, char *argv[]) } done_finalize: + + if(attrFlagList) { + AttrFlagList *attrFlag; + while(attrFlagList) { + attrFlag = attrFlagList->next; + free(attrFlagList->name); + free(attrFlagList); + attrFlagList = attrFlag; + } + } + error = immutil_saImmOmFinalize(immHandle); if (SA_AIS_OK != error) { fprintf(stderr, "error - saImmOmFinalize FAILED: %s\n", saf_error(error)); diff --git a/osaf/tools/safimm/immload/imm_loader.cc b/osaf/tools/safimm/immload/imm_loader.cc --- a/osaf/tools/safimm/immload/imm_loader.cc +++ b/osaf/tools/safimm/immload/imm_loader.cc @@ -18,6 +18,7 @@ #include "imm_loader.hh" #include <iostream> #include <libxml/parser.h> +#include <libxml/xpath.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -26,6 +27,7 @@ #include <configmake.h> #include <logtrace.h> #include <sys/stat.h> +#include <errno.h> #ifndef SA_IMM_ATTR_NO_DUPLICATES @@ -121,6 +123,22 @@ typedef struct ParserStateStruct SaImmHandleT ccbHandle; } ParserState; +bool isXsdLoaded; +std::string xsddir; +std::string xsd; +typedef std::map<std::string, SaImmAttrFlagsT> AttrFlagMap; +AttrFlagMap attrFlagMap; + +static SaImmAttrFlagsT attrFlagMask = (SA_IMM_ATTR_RUNTIME + | SA_IMM_ATTR_CONFIG + | SA_IMM_ATTR_MULTI_VALUE + | SA_IMM_ATTR_WRITABLE + | SA_IMM_ATTR_INITIALIZED + | SA_IMM_ATTR_PERSISTENT + | SA_IMM_ATTR_CACHED + | SA_IMM_ATTR_NOTIFY + | SA_IMM_ATTR_NO_DUPLICATES); + /* Helper functions */ static void addToAttrTypeCache(ParserState*, SaImmValueTypeT); @@ -884,6 +902,13 @@ static void startElementHandler(void* us else if (strcmp((const char*)name, "imm:IMM-contents") == 0) { state->state[state->depth] = IMM_CONTENTS; + char *schema = (char *)getAttributeValue(attrs, (xmlChar *)"noNamespaceSchemaLocation"); + if(!schema) { + schema = (char *)getAttributeValue(attrs, (xmlChar *)"xsi:noNamespaceSchemaLocation"); + } + if(schema) { + xsd = schema; + } } else { @@ -1426,6 +1451,121 @@ static xmlEntityPtr return xmlGetPredefinedEntity(name); } +static inline char *getAttrValue(xmlAttributePtr attr) { + if(!attr || !attr->children) { + return NULL; + } + + return (char *)attr->children->content; +} + +static bool loadXsd(const char *xsdFile) { + struct stat st; + if(stat(xsdFile, &st)) { + if(errno == ENOENT) { + LOG_ER("%s does not exist", xsdFile); + } else { + LOG_ER("stat of %s return error: %d", xsdFile, errno); + } + + return false; + } + // It should be a file or a directory + if(!S_ISREG(st.st_mode)) { + LOG_ER("%s is not a file", xsdFile); + return false; + } + + xmlNodePtr xsdDocRoot; + xmlDocPtr xsdDoc = xmlParseFile(xsdFile); + if(!xsdDoc) { + return false; + } + + bool rc = true; + xmlXPathContextPtr ctx = xmlXPathNewContext(xsdDoc); + if(!ctx) { + rc = false; + goto freedoc; + } + + // Add namespace of the first element + xsdDocRoot = xmlDocGetRootElement(xsdDoc); + if(xsdDocRoot->ns) { + ctx->namespaces = (xmlNsPtr *)malloc(sizeof(xmlNsPtr)); + ctx->namespaces[0] = xsdDocRoot->ns; + ctx->nsNr = 1; + } + + xmlXPathObjectPtr xpathObj; + xpathObj = xmlXPathEval((const xmlChar*)"/xs:schema/xs:simpleType[@name=\"attr-flags\"]/xs:restriction/xs:enumeration", ctx); + if(!xpathObj || !xpathObj->nodesetval) { + rc = false; + goto freectx; + } + + xmlElementPtr element; + xmlAttributePtr attr; + char *id; + char *value; + int size; + + size = xpathObj->nodesetval->nodeNr; + for(int i=0; i<size; i++) { + id = NULL; + value = NULL; + element = (xmlElementPtr)xpathObj->nodesetval->nodeTab[i]; + attr = element->attributes; + while(attr) { + if(!strcmp((char *)attr->name, "ID")) { + id = getAttrValue(attr); + } else if(!strcmp((char *)attr->name, "value")) { + value = getAttrValue(attr); + } + + if(id && value) { + break; + } + + attr = (xmlAttributePtr)attr->next; + } + + if(value) { + char *end; + SaImmAttrFlagsT attrFlag = 0; + if(id) { + if(!strncmp(id, "0x", 2)) { + attrFlag = strtoull(id, &end, 16); + } else { + attrFlag = strtoull(id, &end, 10); + } + + if(*end) { + LOG_WA("INVALID ID(%s) FOR FLAG %s. Unknown attribute flag is set to 0", id, value); + attrFlag = 0; + } + } + + if((attrFlag & ~attrFlagMask) || (attrFlag == 0)) { + attrFlagMap[value] = attrFlag; + } + } + } + + isXsdLoaded = true; + + xmlXPathFreeObject(xpathObj); +freectx: + if(ctx->nsNr) { + free(ctx->namespaces); + } + xmlXPathFreeContext(ctx); +freedoc: + xmlFreeDoc(xsdDoc); + + return rc; +} + /** * Takes a string and returns the corresponding flag */ @@ -1472,7 +1612,24 @@ static SaImmAttrFlagsT charsToFlagsHelpe return SA_IMM_ATTR_NOTIFY; } - LOG_ER("UNKNOWN FLAGS, %s", str); + std::string unflag((char *)str, len); + if(!isXsdLoaded) { + std::string xsdPath = xsddir; + if(xsdPath.size() > 0) + xsdPath.append("/"); + xsdPath.append(xsd); + LOG_WA("Found unknown flag (%s). Trying to load a schema %s", unflag.c_str(), xsdPath.c_str()); + loadXsd(xsdPath.c_str()); + } + + if(isXsdLoaded) { + AttrFlagMap::iterator it = attrFlagMap.find(unflag); + if(it != attrFlagMap.end()) { + return it->second; + } + } + + LOG_ER("UNKNOWN FLAGS, %s", unflag.c_str()); exit(1); } @@ -1881,6 +2038,11 @@ int loadImmXML(std::string xmldir, std:: state.adminInit = 0; state.ccbInit = 0; + isXsdLoaded = false; + xsddir = xmldir; + xsd = ""; + attrFlagMap.clear(); + /* Build the filename */ filename = xmldir; filename.append("/"); ------------------------------------------------------------------------------ Managing the Performance of Cloud-Based Applications Take advantage of what the Cloud has to offer - Avoid Common Pitfalls. Read the Whitepaper. http://pubads.g.doubleclick.net/gampad/clk?id=121054471&iu=/4140/ostg.clktrk _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel