osaf/tools/safimm/immcfg/imm_cfg.c | 29 ++++-
osaf/tools/safimm/immcfg/imm_import.cc | 191 ++++++++++++++++++++++++++++++--
2 files changed, 200 insertions(+), 20 deletions(-)
For forwards compatibility, OpenSAF schema, where unknown attribute flags are
defined, must be provided to immcfg using -X flag.
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
@@ -80,7 +80,8 @@ typedef enum {
// Interface functions which implement -f and -L options (imm_import.cc)
int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int
ccb_safe,
- SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle,
SaImmCcbHandleT *ccbHandle, int mode);
+ SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle,
+ SaImmCcbHandleT *ccbHandle, int mode, const char *xsdPath);
int validateImmXML(const char *xmlfile, int verbose, int mode);
static int imm_operation(int argc, char *argv[]);
@@ -129,6 +130,7 @@ static void usage(const char *progname)
printf("\t--admin-owner-clear\n");
printf("\t--ccb-apply (only in a transaction mode)\n");
printf("\t--ccb-abort (only in a transaction mode)\n");
+ printf("\t-X, --xsd <path_to_schema.xsd>\n");
printf("\nEXAMPLE\n");
printf("\timmcfg -a saAmfNodeSuFailoverMax=7
safAmfNode=Node01,safAmfCluster=1\n");
@@ -160,6 +162,10 @@ static void usage(const char *progname)
printf("\timmcfg\n");
printf("\t\tRunning immcfg in explicit commit mode where immcfg accepts
immcfg commands from command line\n");
printf("\t\tCtrl+D - commit changes and exit, Ctrl+C - abort CCB and
exit\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 */
@@ -1093,6 +1099,7 @@ static int imm_operation(int argc, char
{"admin-owner-clear", no_argument, NULL, 0},
{"ccb-apply", no_argument, NULL, 0},
{"ccb-abort", no_argument, NULL, 0},
+ {"xsd", required_argument, NULL, 'X'},
{0, 0, 0, 0}
};
SaAisErrorT error;
@@ -1115,9 +1122,11 @@ static int imm_operation(int argc, char
unsigned long timeoutVal = 60;
attr_notify_t attrNotify = NOTIFY_UNDEFINED;
+ char *xsdPath = NULL;
+
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "a:c:f:t:dhmvuL:o:", long_options,
&option_index);
+ c = getopt_long(argc, argv, "a:c:f:t:dhmvuL:o:X:",
long_options, &option_index);
if (c == -1) /* have all command-line options have been
parsed? */
break;
@@ -1225,6 +1234,16 @@ static int imm_operation(int argc, char
adminOwnerName =
(SaImmAdminOwnerNameT)malloc(strlen(optarg) + 1);
strcpy(adminOwnerName, optarg);
break;
+ case 'X':
+ if(xsdPath) {
+ fprintf(stderr, "XSD path is already set\n");
+ if(transaction_mode)
+ return -1;
+ else
+ exit(EXIT_FAILURE);
+ }
+ xsdPath = strdup(optarg);
+ break;
default:
fprintf(stderr, "Try '%s --help' for more
information\n", argv[0]);
if(transaction_mode)
@@ -1270,7 +1289,7 @@ static int imm_operation(int argc, char
if (op == LOAD_IMMFILE) {
VERBOSE_INFO("importImmXML(xmlFilename=%s, verbose=%d)\n",
xmlFilename, verbose);
rc = importImmXML(xmlFilename, adminOwnerName, verbose,
ccb_safe,
- &immHandle, &ownerHandle, &ccbHandle,
transaction_mode);
+ &immHandle, &ownerHandle, &ccbHandle,
transaction_mode, xsdPath);
if(transaction_mode) {
if(rc) {
fprintf(stderr, "CCB is aborted\n");
@@ -1478,6 +1497,10 @@ static int imm_operation(int argc, char
}
}
}
+ if(xsdPath) {
+ free(xsdPath);
+ xsdPath = NULL;
+ }
return 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>
@@ -59,7 +63,8 @@ static char base64_dec_table[] = {
extern "C"
{
int importImmXML(char* xmlfileC, char* adminOwnerName, int verbose, int
ccb_safe,
- SaImmHandleT *immHandle, SaImmAdminOwnerHandleT
*ownerHandle, SaImmCcbHandleT *ccbHandle, int mode);
+ SaImmHandleT *immHandle, SaImmAdminOwnerHandleT
*ownerHandle,
+ SaImmCcbHandleT *ccbHandle, int mode, const char
*xsdPath);
int validateImmXML(const char *xmlfile, int verbose, int mode);
}
@@ -143,6 +148,10 @@ typedef struct ParserStateStruct {
int parsingStatus; /* 0 = ok */
} ParserState;
+bool isXsdLoaded = false;
+static const char *imm_xsd_file;
+typedef std::set<std::string> AttrFlagSet;
+AttrFlagSet attrFlagSet;
/* Prototypes */
@@ -1228,6 +1237,144 @@ 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 *value;
+ int size;
+
+ size = xpathObj->nodesetval->nodeNr;
+ for(int i=0; i<size; i++) {
+ value = NULL;
+ element = (xmlElementPtr)xpathObj->nodesetval->nodeTab[i];
+ attr = element->attributes;
+ while(attr) {
+ if(!strcmp((char *)attr->name, "value")) {
+ value = getAttrValue(attr);
+ }
+
+ if(value) {
+ break;
+ }
+
+ attr = (xmlAttributePtr)attr->next;
+ }
+
+ if(value) {
+ if(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")) {
+ attrFlagSet.insert(value);
+ }
+ }
+ }
+
+ 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
*/
@@ -1360,6 +1507,13 @@ 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);
+ stopParser(state);
+ state->parsingStatus = 1;
+ }
+ }
} else {
LOG_ER("UNKNOWN TAG! (%s)", name);
stopParser(state);
@@ -1776,11 +1930,11 @@ static void charactersHandler(void* user
case FLAG:
{
SaImmAttrFlagsT flg = charsToFlagsHelper(chars,
(size_t)len);
- if(flg)
- state->attrFlags |= flg;
- else {
+ if(flg == 0xffffffffffffffff) {
stopParser(state);
state->parsingStatus = 1;
+ } else {
+ state->attrFlags |= flg;
}
}
break;
@@ -1839,18 +1993,17 @@ static SaImmAttrFlagsT charsToFlagsHelpe
return SA_IMM_ATTR_NO_DANGLING;
}
- /* strlen("SA_NO_DUPLICATES") == 16 (the longest flag name)
- * A bit longer string is taken to log, max 20 characters.
- */
- char unknown[21];
- if(len > 20)
- len = 20;
- memcpy(unknown, str, len);
- unknown[len] = 0;
-
- LOG_ER("UNKNOWN FLAGS, %s", unknown);
-
- return 0;
+ std::string flag((char *)str, len);
+ if(isXsdLoaded) {
+ AttrFlagSet::iterator it = attrFlagSet.find(flag);
+ if(it != attrFlagSet.end()) {
+ return 0;
+ }
+ }
+
+ LOG_ER("UNKNOWN FLAGS, %s", flag.c_str());
+
+ return 0xffffffffffffffff;
}
/**
@@ -2506,7 +2659,8 @@ int loadImmXML(const char *xmlfile)
// 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,
- SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle,
SaImmCcbHandleT *ccbHandle, int mode)
+ SaImmHandleT *immHandle, SaImmAdminOwnerHandleT *ownerHandle,
+ SaImmCcbHandleT *ccbHandle, int mode, const char *xsdPath)
{
imm_import_adminOwnerName = adminOwnerName;
imm_import_verbose = verbose;
@@ -2517,6 +2671,9 @@ int importImmXML(char* xmlfileC, char* a
imm_import_ccbHandle = ccbHandle;
transaction_mode = mode;
+ imm_xsd_file = xsdPath;
+ isXsdLoaded = false;
+ attrFlagSet.clear();
LOG_IN("file: %s adminOwner: %s", xmlfileC, adminOwnerName);
------------------------------------------------------------------------------
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensaf-devel