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

Reply via email to