/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include "isns_server.h"
#include "isns_obj.h"
#include "isns_log.h"
#if LIBXML_VERSION >= 20904
#define XMLSTRING_CAST (const char *)
#else
#define XMLSTRING_CAST (const xmlChar *)
#endif
/*
* external variables
*/
extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE];
extern const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE];
extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
extern char data_store[MAXPATHLEN];
/*
* local variables
*/
static xmlDocPtr xml_doc = NULL;
static char *xml_file = NULL;
static char *xml_tmp_file = NULL;
static char *xml_bak_file = NULL;
static const int OBJ_DTD_ORDER[MAX_OBJ_TYPE_FOR_SIZE] = {
0,
1, /* OBJ_ENTITY */
2, /* OBJ_ISCSI */
3, /* OBJ_PORTAL */
4, /* OBJ_PG */
5, /* OBJ_DD */
6, /* OBJ_DDS */
0, /* MAX_OBJ_TYPE */
0, /* OBJ_DUMMY1 */
0, /* OBJ_DUMMY2 */
0, /* OBJ_DUMMY3 */
0, /* OBJ_DUMMY4 */
12, /* OBJ_ASSOC_ISCSI */
14, /* OBJ_ASSOC_DD */
};
#define DEF_XML_ROOT(ISNS_DATA, VENDOR, SMI, VERSION, ONE_DOT_O) \
(xmlChar *)ISNS_DATA, \
(xmlChar *)VENDOR, \
(xmlChar *)SMI, \
(xmlChar *)VERSION, \
(xmlChar *)ONE_DOT_O
static const xmlChar *xml_root[] = {
#include "data.def"
};
#define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) (xmlChar *)TAG,
static const xmlChar* xmlTag[] = {
#include "data.def"
};
#define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) TYPE,
static const char *xmlType[] = {
#include "data.def"
};
#define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) ARG1,
static const int xmlArg1[] = {
#include "data.def"
};
#define DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) ARG2,
static const int xmlArg2[] = {
#include "data.def"
};
#define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) TYPE,
static const unsigned char xmlPropType[] = {
#include "data.def"
};
#define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) (xmlChar *)NAME,
static const xmlChar *xmlPropName[] = {
#include "data.def"
};
#define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) TAG,
static const int xmlPropTag[] = {
#include "data.def"
};
#define DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) ID,
static const int xmlPropID[] = {
#include "data.def"
};
#define ARRAY_LENGTH(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
/*
* ****************************************************************************
*
* get_index_by_name:
* find the index in the global tables for the name of an attribute.
*
* name - the name of an attribute.
* return - index or -1 for error.
*
* ****************************************************************************
*/
static int
get_index_by_name(
const xmlChar *name
)
{
int i;
for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) {
if (xmlStrEqual(xmlTag[i], name)) {
return (i);
}
}
return (-1);
}
/*
* ****************************************************************************
*
* get_index_by_otype:
* find the index in the global tables for the type of an object.
*
* name - the type of an object.
* return - index or -1 for error.
*
* ****************************************************************************
*/
static int
get_index_by_otype(
int otype
)
{
int i;
for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) {
if (xmlArg1[i] == otype && xmlType[i][0] == 'o') {
return (i);
}
}
return (-1);
}
/*
* ****************************************************************************
*
* get_index_by_tag:
* find the index in the global tables for the tag of an attribute.
*
* name - the tag of an attribute.
* return - index or -1 for error.
*
* ****************************************************************************
*/
static int
get_index_by_tag(
int tag
)
{
int i;
for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) {
if (xmlArg1[i] == tag &&
xmlType[i][0] != 'o' &&
xmlType[i][0] != 'a') {
return (i);
}
}
return (-1);
}
/*
* ****************************************************************************
*
* get_xml_doc:
* open the xml file and assign the global xml doc if the xml file
* is not opened, set the doc pointer with the opened xml file for
* returnning.
*
* docp - the doc pointer for returning.
* return - error code.
*
* ****************************************************************************
*/
static int
get_xml_doc(
xmlDocPtr *docp
)
{
int ec = 0;
if (xml_doc == NULL) {
/* validate the xml file */
/* open the xml file */
xml_doc = xmlParseFile(xml_file);
}
*docp = xml_doc;
if (xml_doc == NULL) {
ec = ISNS_RSP_INTERNAL_ERROR;
}
return (ec);
}
/*
* ****************************************************************************
*
* close_xml_doc:
* close the global xml doc and ignore any changes that has been
* made in it.
*
* ****************************************************************************
*/
static void
close_xml_doc(
)
{
if (xml_doc) {
/* just close it */
xmlFreeDoc(xml_doc);
xml_doc = NULL;
}
}
/*
* ****************************************************************************
*
* convert_xml2attr:
* convert a xml data to a TLV format isns attribute.
*
* tag - the tag of attribute.
* type - the data type of the xml data.
* value - the xml data.
* attr - TLV format attribute for returning.
* return - error code.
*
* ****************************************************************************
*/
static int
convert_xml2attr(
const int tag,
const unsigned char type,
xmlChar *value,
isns_attr_t *attr
)
{
uint32_t len;
int ec = 0;
attr->tag = tag;
switch (type) {
case 'u':
/* 4-bytes non-negative integer */
attr->len = 4;
attr->value.ui = atoi((const char *)value);
break;
case 's':
/* literal string */
len = strlen((char *)value);
len += 4 - (len % 4);
attr->len = len;
attr->value.ptr = (uchar_t *)malloc(attr->len);
if (attr->value.ptr != NULL) {
(void) strcpy((char *)attr->value.ptr,
(char *)value);
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
break;
case 'p':
/* IPv6 block data */
attr->len = sizeof (in6_addr_t);
attr->value.ip = (in6_addr_t *)malloc(attr->len);
if (attr->value.ip != NULL) {
(void) inet_pton(AF_INET6,
(char *)value,
attr->value.ip);
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
break;
default:
break;
}
return (ec);
}
/*
* ****************************************************************************
*
* convert_attr2xml:
* convert a TLV format isns attribute to xml node format.
*
* node - the xml node where the new node is being added to.
* attr - the TLV format attribute.
* name - the name of the attribute in xml node.
* type - the data type of the attribute.
* elm_flag - 0: adding a xml attlist.
* 1: adding a xml child node.
* 2: adding a previous sibling node.
* 3: adding a xml content node.
* 4: adding a xml attribute.
* return - xml node.
*
* ****************************************************************************
*/
static xmlNodePtr
convert_attr2xml(
xmlNodePtr node,
const isns_attr_t *attr,
const xmlChar *name,
const char type,
const int elm_flag
)
{
xmlChar buff[INET6_ADDRSTRLEN + 1] = { 0 };
xmlChar *value = NULL;
xmlNodePtr child = NULL;
switch (type) {
case 'u':
/* 4-bytes non-negative integer */
if (xmlStrPrintf(buff, sizeof (buff),
XMLSTRING_CAST "%u",
attr->value.ui) > 0) {
value = (xmlChar *)&buff;
}
break;
case 's':
/* literal string */
value = (xmlChar *)attr->value.ptr;
break;
case 'p':
/* IPv6 block data */
value = (xmlChar *)inet_ntop(AF_INET6,
(char *)attr->value.ip,
(char *)buff,
sizeof (buff));
break;
default:
break;
}
if (!value) {
return (NULL);
}
switch (elm_flag) {
case 0: /* attlist */
if (xmlSetProp(node, name, value)) {
child = node;
}
break;
case 1: /* child element */
child = xmlNewChild(node, NULL, name, value);
break;
case 2: /* prev sibling element */
child = xmlNewNode(NULL, name);
if (child != NULL &&
xmlAddPrevSibling(node, child) == NULL) {
xmlFreeNode(child);
node = NULL;
} else {
node = child;
}
/* LINTED E_CASE_FALLTHRU */
case 3: /* set content */
if (node) {
xmlNodeSetContent(node, value);
}
child = node;
break;
case 4: /* new attr value */
if (xmlSetProp(node, name, value)) {
child = node;
}
break;
default:
ASSERT(0);
break;
}
return (child);
}
/*
* ****************************************************************************
*
* parse_xml_prop:
* parse the properties of a xml node and convert them to the attributes
* of an isns object, these xml properties are the UID attribute and
* key attributes of the isns object.
*
* node - the xml node that contains the properties.
* obj - the isns object.
* i - the index of the attribute in the global tables.
* return - error code.
*
* ****************************************************************************
*/
static int
parse_xml_prop(
xmlNodePtr node,
isns_obj_t *obj,
int i
)
{
int ec = 0;
const char *props = &xmlType[i][1];
const xmlChar *prop_name;
xmlChar *prop_value;
unsigned char prop_type;
int prop_tag;
int prop_id;
char prop;
int j;
j = 0;
prop = props[j ++];
while (ec == 0 &&
prop >= 'a' && prop <= 'z') {
prop -= 'a';
prop_id = xmlPropID[prop];
prop_tag = xmlPropTag[prop];
prop_name = xmlPropName[prop];
prop_type = xmlPropType[prop];
prop_value = xmlGetProp(node, prop_name);
if (prop_value) {
ec = convert_xml2attr(
prop_tag,
prop_type,
prop_value,
&(obj->attrs[prop_id]));
xmlFree(prop_value);
}
prop = props[j ++];
}
return (ec);
}
/*
* ****************************************************************************
*
* parse_xml_attr:
* parse a xml node and convert it to one isns object attribute.
* this attribute is the non-key attribute of the isns object.
*
* node - the xml node.
* obj - the isns object.
* i - the index of the attribute in the global tables.
* return - error code.
*
* ****************************************************************************
*/
static int
parse_xml_attr(
xmlNodePtr node,
isns_obj_t *obj,
int i
)
{
int ec = 0;
const unsigned char attr_type = xmlType[i][0];
const int attr_tag = xmlArg1[i];
const int attr_id = xmlArg2[i];
xmlChar *attr_value;
attr_value = xmlNodeGetContent(node);
if (attr_value) {
ec = convert_xml2attr(
attr_tag,
attr_type,
attr_value,
&(obj->attrs[attr_id]));
xmlFree(attr_value);
}
return (ec);
}
/*
* ****************************************************************************
*
* parse_xml_obj:
* parse one isns object from the xml doc.
*
* nodep - the pointer of the xml node for parsing.
* objp - the pointer of isns object for returning.
* return - error code.
*
* ****************************************************************************
*/
static int
parse_xml_obj(
xmlNodePtr *nodep,
isns_obj_t **objp
)
{
int ec = 0;
int i, j;
xmlNodePtr node = *nodep;
xmlNodePtr children;
isns_obj_t *obj = *objp;
while (node && ec == 0) {
if (node->type == XML_ELEMENT_NODE) {
children = node->children;
i = get_index_by_name(node->name);
ASSERT(i >= 0);
j = xmlType[i][0];
if (j == 'o' && obj == NULL) {
obj = obj_calloc(xmlArg1[i]);
if (obj == NULL) {
ec = ISNS_RSP_INTERNAL_ERROR;
break;
}
if ((ec = parse_xml_prop(node, obj, i)) == 0 &&
(children == NULL ||
(ec = parse_xml_obj(&children, &obj)) ==
0)) {
if (children != NULL &&
children != node->children) {
*nodep = children;
}
*objp = obj;
} else {
free_object(obj);
}
break;
/* LINTED E_NOP_IF_STMT */
} else if (j == 'o') {
} else if (j != 0) {
ASSERT(obj);
if (children != NULL) {
ec = parse_xml_attr(children, obj, i);
*nodep = children;
} else {
/* assign a default value */
*nodep = node;
}
} else {
/* unknown xml node */
break;
}
/* LINTED E_NOP_ELSE_STMT */
} else {
/* carry return or blank spaces, skip it */
}
node = node->next;
}
return (ec);
}
/*
* ****************************************************************************
*
* locate_xml_node:
* locate the xml node from xml doc by matching the object UID.
*
* doc - the xml doc.
* otype - the matching object type.
* match_uid - the matching object UID.
* node - the pointer of matched xml node for returning.
* context - the xml context for matching process.
* result - the xml result for matching process.
* return - error code.
*
* ****************************************************************************
*/
static int
locate_xml_node(
xmlDocPtr doc,
int otype,
int match_uid,
xmlNodePtr *node,
xmlXPathContextPtr *context,
xmlXPathObjectPtr *result
)
{
int ec = 0;
xmlNodeSetPtr nodeset;
xmlNodePtr curr;
xmlChar expr[32] = { (xmlChar)'/', (xmlChar)'/', 0 };
char prop;
const xmlChar *prop_name;
xmlChar *prop_value;
int uid;
int i, j;
*node = NULL;
i = get_index_by_otype(otype);
ASSERT(i >= 0);
*context = xmlXPathNewContext(doc);
if (*context &&
xmlStrPrintf(&expr[2], 30, XMLSTRING_CAST "%s",
xmlTag[i]) != -1) {
*result = xmlXPathEvalExpression(expr, *context);
if (*result) {
prop = xmlArg2[i] - 'a';
prop_name = xmlPropName[prop];
ASSERT(xmlPropType[prop] == 'u');
nodeset = (*result)->nodesetval;
for (j = 0;
nodeset && (j < nodeset->nodeNr);
j++) {
curr = nodeset->nodeTab[j];
prop_value = xmlGetProp(curr, prop_name);
if (prop_value) {
uid = atoi((const char *)prop_value);
xmlFree(prop_value);
if (uid == match_uid) {
/* found it */
*node = curr;
return (ec);
}
}
}
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
} else {
ec = ISNS_RSP_INTERNAL_ERROR;
}
if (*result) {
xmlXPathFreeObject(*result);
*result = NULL;
}
if (*context) {
xmlXPathFreeContext(*context);
*context = NULL;
}
return (ec);
}
/*
* ****************************************************************************
*
* make_xml_node:
* generate a xml node for presenting an isns object.
*
* obj - an isns object.
* return - the xml node.
*
* ****************************************************************************
*/
static xmlNodePtr
make_xml_node(
const isns_obj_t *obj
)
{
const isns_attr_t *attr;
xmlNodePtr node;
const char *props;
char prop;
const xmlChar *name;
unsigned char type;
int prop_id;
int i, j;
i = get_index_by_otype(obj->type);
ASSERT(i >= 0);
node = xmlNewNode(NULL, xmlTag[i]);
if (!node) {
return (NULL);
}
/* generate xml attributes of the node */
props = &xmlType[i][1];
prop = *(props ++);
while (prop >= 'a' && prop <= 'z') {
prop -= 'a';
prop_id = xmlPropID[prop];
name = xmlPropName[prop];
type = xmlPropType[prop];
attr = &obj->attrs[prop_id];
if (!convert_attr2xml(node, attr, name, type, 0)) {
xmlFreeNode(node);
return (NULL);
}
/* attr->tag = 0; */
prop = *(props ++);
}
/* generate sub elements for isns attributes of the object */
i = 0;
while (i < NUM_OF_ATTRS[obj->type]) {
attr = &obj->attrs[i ++];
j = get_index_by_tag(attr->tag);
if (j >= 0) {
name = xmlTag[j];
type = xmlType[j][0];
if (!convert_attr2xml(node, attr, name, type, 1)) {
xmlFreeNode(node);
return (NULL);
}
}
}
return (node);
}
/*
* ****************************************************************************
*
* xml_init_data:
* initialization of the xml data store.
*
* return - error code.
*
* ****************************************************************************
*/
static int
xml_init_data(
)
{
#define XML_PATH "/etc/isns"
#define XML_FILE_NAME "/isnsdata.xml"
#define XML_DOT_TMP ".tmp"
#define XML_DOT_BAK ".bak"
int fd;
xmlDocPtr doc;
xmlNodePtr root;
int len;
char *xml_path, *p = NULL;
char *cwd = NULL;
int has_bak = 0;
/* cannot reset the xml file when server is running */
if (xml_file != NULL) {
return (1);
}
/* set the data store file name along with the backup */
/* file name and temporary file name */
len = strlen(data_store);
if (len > 0) {
xml_file = data_store;
p = strdup(xml_file);
xml_bak_file = (char *)malloc(len + 5);
xml_tmp_file = (char *)malloc(len + 5);
if (p != NULL &&
xml_bak_file != NULL &&
xml_tmp_file != NULL) {
xml_path = dirname(p);
(void) strcpy(xml_bak_file, xml_file);
(void) strcat(xml_bak_file, XML_DOT_BAK);
(void) strcpy(xml_tmp_file, xml_file);
(void) strcat(xml_tmp_file, XML_DOT_TMP);
} else {
return (1);
}
} else {
xml_path = XML_PATH;
xml_file = XML_PATH XML_FILE_NAME;
xml_bak_file = XML_PATH XML_FILE_NAME XML_DOT_BAK;
xml_tmp_file = XML_PATH XML_FILE_NAME XML_DOT_TMP;
}
/* save current working directory */
cwd = getcwd(NULL, MAXPATHLEN);
if (cwd == NULL) {
return (1);
}
/* check access permission on data store directory */
if (chdir(xml_path) != 0) {
if (errno == ENOENT) {
if (mkdir(xml_path, S_IRWXU) != 0 ||
chdir(xml_path) != 0) {
return (1);
}
} else {
return (1);
}
}
/* go back to original working directory */
(void) chdir(cwd);
free(cwd);
free(p);
/* do not keep blank spaces */
(void) xmlKeepBlanksDefault(0);
/* remove the tmp file if it exists */
if (access(xml_tmp_file, F_OK) == 0) {
(void) remove(xml_tmp_file);
}
/* test if we can write the bak file */
fd = open(xml_bak_file, O_RDWR);
if (fd == -1) {
fd = open(xml_bak_file, O_RDWR | O_CREAT,
S_IRUSR | S_IWUSR);
if (fd == -1) {
return (1);
} else {
(void) close(fd);
(void) remove(xml_bak_file);
}
} else {
has_bak = 1;
(void) close(fd);
}
/* Test if we have the data store file, create an empty */
/* data store if we do not have the data store file and */
/* the backup data store. */
fd = open(xml_file, O_RDWR);
if (fd == -1) {
if (has_bak == 0) {
doc = xmlNewDoc(BAD_CAST "1.0");
root = xmlNewNode(NULL, xml_root[0]);
if (doc != NULL &&
root != NULL &&
xmlSetProp(root, xml_root[1], xml_root[2]) !=
NULL &&
xmlSetProp(root, xml_root[3], xml_root[4]) !=
NULL) {
(void) xmlDocSetRootElement(doc, root);
if (xmlSaveFormatFile(xml_file, doc, 1) == -1) {
xmlFreeDoc(doc);
return (-1);
}
xmlFreeDoc(doc);
} else {
if (doc != NULL) {
xmlFreeDoc(doc);
}
if (root != NULL) {
xmlFreeNode(root);
}
return (1);
}
} else {
isnslog(LOG_WARNING, "get_xml_doc",
"initializing with backup data");
if (rename(xml_bak_file, xml_file) != 0) {
return (1);
}
}
} else {
(void) close(fd);
}
return (0);
}
/*
* ****************************************************************************
*
* xml_load_obj:
* load an isns object from the xml data store.
*
* p - the pointer of current xml node.
* objp - the pointer of the object for returning.
* level - the direction of xml parsing for returning.
* return - error code.
*
* ****************************************************************************
*/
static int
xml_load_obj(
void **p,
isns_obj_t **objp,
uchar_t *level
)
{
xmlDocPtr doc = NULL;
xmlNodePtr node = (xmlNodePtr)*p;
int ec = 0;
*objp = NULL;
if (node == NULL) {
*level = '^';
ec = get_xml_doc(&doc);
if (doc == NULL) {
return (ec);
}
node = xmlDocGetRootElement(doc);
if (node != NULL) {
node = node->children;
}
} else if (node->children != NULL) {
*level = '>';
node = node->children;
} else if (node->next != NULL) {
*level = 'v';
node = node->next;
} else {
*level = 'v';
while (node != NULL && node->next == NULL) {
if (node->type == XML_ELEMENT_NODE) {
*level = '<';
}
node = node->parent;
}
if (node != NULL) {
node = node->next;
}
}
/* there is a node, parse it */
if (node) {
ec = parse_xml_obj(&node, objp);
*p = (void *)node;
}
if (ec == 0 && *objp != NULL) {
ec = update_deref_obj(*objp);
if (ec != 0) {
free_object(*objp);
*objp = NULL;
}
}
/* no object available, close the xml doc */
if (*objp == NULL) {
(void) close_xml_doc();
}
return (ec);
}
/*
* ****************************************************************************
*
* xml_add_obj:
* add an isns object to the xml data store.
*
* obj - the object being added.
* return - error code.
*
* ****************************************************************************
*/
static int
xml_add_obj(
const isns_obj_t *obj
)
{
int ec = 0;
xmlDocPtr doc;
xmlXPathContextPtr context = NULL;
xmlXPathObjectPtr result = NULL;
xmlNodePtr node, prev;
xmlNodePtr candidate;
uint32_t puid, parent_type;
int i;
/* get the xml doc */
ec = get_xml_doc(&doc);
if (doc == NULL) {
goto add_done;
}
/* create the candidate node */
candidate = make_xml_node(obj);
if (candidate == NULL) {
ec = ISNS_RSP_INTERNAL_ERROR;
goto add_done;
}
/* locate the position */
parent_type = TYPE_OF_PARENT[obj->type];
if (parent_type > 0) {
puid = get_parent_uid(obj);
ec = locate_xml_node(doc, parent_type, puid,
&node, &context, &result);
} else {
node = xmlDocGetRootElement(doc);
}
/* cannot locate the point for inserting the node */
if (node == NULL) {
xmlFreeNode(candidate);
ec = ISNS_RSP_INTERNAL_ERROR;
goto add_done;
}
/* add it with the apporiate child order */
if (node->children) {
node = node->children;
while (node) {
if (node->type == XML_ELEMENT_NODE) {
i = get_index_by_name(node->name);
ASSERT(i >= 0);
if (xmlType[i][0] == 'o' &&
OBJ_DTD_ORDER[xmlArg1[i]] >=
OBJ_DTD_ORDER[obj->type]) {
break;
}
}
prev = node;
node = node->next;
}
if (node == NULL) {
node = xmlAddNextSibling(prev, candidate);
} else {
node = xmlAddPrevSibling(node, candidate);
}
} else {
node = xmlAddChild(node, candidate);
}
if (node == NULL) {
/* Failed, free the candidate node. */
xmlFreeNode(candidate);
ec = ISNS_RSP_INTERNAL_ERROR;
}
add_done:
if (result) {
xmlXPathFreeObject(result);
}
if (context) {
xmlXPathFreeContext(context);
}
return (ec);
}
/*
* ****************************************************************************
*
* xml_modify_obj:
* modify an isns object in the xml data store.
*
* obj - the new object.
* return - error code.
*
* ****************************************************************************
*/
static int
xml_modify_obj(
const isns_obj_t *obj
)
{
int ec = 0;
xmlDocPtr doc;
xmlXPathContextPtr context = NULL;
xmlXPathObjectPtr result = NULL;
xmlNodePtr node, child;
const char *props;
char prop;
int prop_id;
int prop_tag;
const xmlChar *name;
unsigned char type;
const isns_attr_t *attr;
int i, j, k;
int make_child;
/* get the doc pointer */
ec = get_xml_doc(&doc);
if (doc == NULL) {
return (ec);
}
/* locate the node for the object */
i = get_index_by_otype(obj->type);
ASSERT(i >= 0);
prop = xmlArg2[i] - 'a';
prop_id = xmlPropID[prop];
attr = &obj->attrs[prop_id];
ec = locate_xml_node(doc,
obj->type,
attr->value.ui,
&node, &context, &result);
/* modify it */
if (node != NULL) {
props = &xmlType[i][1];
prop = *(props ++);
while (prop >= 'a' && prop <= 'z') {
prop -= 'a';
prop_id = xmlPropID[prop];
prop_tag = xmlPropTag[prop];
attr = &obj->attrs[prop_id];
/* no need to update the key attributes, skip it. */
/* btw, dd and dd-set names are non-key attributes. */
if (prop_tag == ISNS_DD_NAME_ATTR_ID ||
prop_tag == ISNS_DD_SET_NAME_ATTR_ID) {
name = xmlPropName[prop];
type = xmlPropType[prop];
if (!convert_attr2xml(node,
attr, name, type, 4)) {
ec = ISNS_RSP_INTERNAL_ERROR;
goto modify_done;
}
}
/* attr->tag = 0; */
prop = *(props ++);
}
/* set the child */
child = node->children;
if (child == NULL) {
make_child = 1;
} else {
make_child = 0;
}
for (i = 0; i < NUM_OF_ATTRS[obj->type]; i++) {
attr = &obj->attrs[i];
j = get_index_by_tag(attr->tag);
if (j < 0) {
continue;
}
name = xmlTag[j];
type = xmlType[j][0];
if (make_child == 1) {
/* make a child node */
if (!convert_attr2xml(node, attr,
name, type, 1)) {
ec = ISNS_RSP_INTERNAL_ERROR;
goto modify_done;
}
continue;
}
while (child) {
if (child->type == XML_ELEMENT_NODE) {
k = get_index_by_name(child->name);
ASSERT(k >= 0);
if (xmlType[k][0] == 'o' ||
xmlType[k][0] == 'a' ||
xmlArg1[k] > attr->tag) {
if (!convert_attr2xml(child,
attr, name, type, 2)) {
/* internal error */
ec = 11;
goto modify_done;
}
break;
} else if (xmlArg1[k] == attr->tag) {
/* replace content */
if (!convert_attr2xml(child,
attr, name, type, 3)) {
/* internal error */
ec = 11;
goto modify_done;
}
break;
}
}
child = child->next;
}
if (child == NULL) {
/* make a child node */
if (!convert_attr2xml(node, attr,
name, type, 1)) {
ec = ISNS_RSP_INTERNAL_ERROR;
goto modify_done;
}
}
}
} else {
/* This case is for registering a node which has */
/* membership in one or more non-default DD(s). */
ec = xml_add_obj(obj);
}
modify_done:
if (result) {
xmlXPathFreeObject(result);
}
if (context) {
xmlXPathFreeContext(context);
}
return (ec);
}
/*
* ****************************************************************************
*
* xml_delete_obj:
* delete an isns object from the xml data store.
*
* obj - the object being deleted.
* return - error code.
*
* ****************************************************************************
*/
static int
xml_delete_obj(
const isns_obj_t *obj
)
{
int ec = 0;
xmlDocPtr doc;
xmlXPathContextPtr context = NULL;
xmlXPathObjectPtr result = NULL;
xmlNodePtr node;
isns_type_t otype;
uint32_t uid;
/* get the xml doc */
ec = get_xml_doc(&doc);
if (doc == NULL) {
return (ec);
}
otype = obj->type;
#ifdef WRITE_DATA_ASYNC
/* it is a thin clone */
uid = obj->attrs[0].value.ui;
#else
uid = get_obj_uid(obj);
#endif
/* locate the object */
ec = locate_xml_node(doc,
otype,
uid,
&node, &context, &result);
/* destroy it */
if (node) {
xmlUnlinkNode(node);
xmlFreeNode(node);
}
if (result) {
xmlXPathFreeObject(result);
}
if (context) {
xmlXPathFreeContext(context);
}
return (ec);
}
/*
* ****************************************************************************
*
* xml_delete_assoc:
* delete a DD or DD-set membership from the xml data store.
*
* assoc - the membership being deleted.
* return - error code.
*
* ****************************************************************************
*/
static int
xml_delete_assoc(
const isns_obj_t *assoc
)
{
int ec = 0;
xmlDocPtr doc;
xmlXPathContextPtr context = NULL;
xmlXPathObjectPtr result = NULL;
xmlNodePtr node;
uint32_t puid, parent_type;
uint32_t uid, match_uid;
char prop;
const xmlChar *prop_name;
xmlChar *prop_value;
int i;
/* get the xml doc */
ec = get_xml_doc(&doc);
if (doc == NULL) {
return (ec);
}
/* get the container object UID */
parent_type = TYPE_OF_PARENT[assoc->type];
ASSERT(parent_type != 0);
puid = get_parent_uid(assoc);
ASSERT(puid != 0);
/* get the member object UID */
i = get_index_by_otype(assoc->type);
prop = xmlArg2[i] - 'a';
prop_name = xmlPropName[prop];
match_uid = assoc->attrs[UID_ATTR_INDEX[assoc->type]].value.ui;
/* locate the container object */
ec = locate_xml_node(doc, parent_type, puid,
&node, &context, &result);
/* get the membership nodes */
if (node != NULL) {
node = node->children;
}
/* get the matching membership node */
while (node) {
if (node->type == XML_ELEMENT_NODE) {
i = get_index_by_name(node->name);
ASSERT(i >= 0);
if (xmlType[i][0] == 'o' &&
xmlArg1[i] == assoc->type) {
prop_value = xmlGetProp(node, prop_name);
if (prop_value) {
uid = atoi((const char *)prop_value);
xmlFree(prop_value);
if (uid == match_uid) {
break;
}
}
}
}
node = node->next;
}
/* destroy it */
if (node) {
xmlUnlinkNode(node);
xmlFreeNode(node);
}
if (result) {
xmlXPathFreeObject(result);
}
if (context) {
xmlXPathFreeContext(context);
}
return (ec);
}
/*
* ****************************************************************************
*
* xml_update_commit:
* backup the current written file and commit all updates from
* the xml doc to the written file.
*
* return - error code.
*
* ****************************************************************************
*/
static int
xml_update_commit(
)
{
int ec = 0;
if (xml_doc) {
/* write to tmp file */
if (xmlSaveFormatFile(xml_tmp_file, xml_doc, 1) == -1 ||
/* backup the current file */
rename(xml_file, xml_bak_file) != 0 ||
/* rename the tmp file to the current file */
rename(xml_tmp_file, xml_file) != 0) {
/* failed saving file */
ec = ISNS_RSP_INTERNAL_ERROR;
}
/* close the xml_doc */
xmlFreeDoc(xml_doc);
xml_doc = NULL;
}
return (ec);
}
/*
* ****************************************************************************
*
* xml_update_retreat:
* ignore all of updates in the xml doc.
*
* return - 0: always successful.
*
* ****************************************************************************
*/
static int
xml_update_retreat(
)
{
if (xml_doc) {
/* close the xml_doc */
xmlFreeDoc(xml_doc);
xml_doc = NULL;
}
return (0);
}