xref: /illumos-gate/usr/src/cmd/isns/isnsd/xml/data.c (revision 438b5f69eb4f998015cc0835f19f2f80663f2f53)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <libgen.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <libxml/parser.h>
40 #include <libxml/xpath.h>
41 
42 #include "isns_server.h"
43 #include "isns_obj.h"
44 #include "isns_log.h"
45 
46 /*
47  * external variables
48  */
49 extern const int NUM_OF_ATTRS[MAX_OBJ_TYPE_FOR_SIZE];
50 extern const int TYPE_OF_PARENT[MAX_OBJ_TYPE_FOR_SIZE];
51 extern const int UID_ATTR_INDEX[MAX_OBJ_TYPE_FOR_SIZE];
52 
53 extern char data_store[MAXPATHLEN];
54 
55 /*
56  * local variables
57  */
58 static xmlDocPtr xml_doc = NULL;
59 static char *xml_file = NULL;
60 static char *xml_tmp_file = NULL;
61 static char *xml_bak_file = NULL;
62 
63 static const int OBJ_DTD_ORDER[MAX_OBJ_TYPE_FOR_SIZE] = {
64 	0,
65 	1,	/* OBJ_ENTITY */
66 	2,	/* OBJ_ISCSI */
67 	3,	/* OBJ_PORTAL */
68 	4,	/* OBJ_PG */
69 	5,	/* OBJ_DD */
70 	6,	/* OBJ_DDS */
71 	0,	/* MAX_OBJ_TYPE */
72 	0,	/* OBJ_DUMMY1 */
73 	0,	/* OBJ_DUMMY2 */
74 	0,	/* OBJ_DUMMY3 */
75 	0,	/* OBJ_DUMMY4 */
76 	12,	/* OBJ_ASSOC_ISCSI */
77 	14,	/* OBJ_ASSOC_DD */
78 };
79 
80 #define	DEF_XML_ROOT(ISNS_DATA, VENDOR, SMI, VERSION, ONE_DOT_O) \
81 	(xmlChar *)ISNS_DATA, \
82 	(xmlChar *)VENDOR, \
83 	(xmlChar *)SMI, \
84 	(xmlChar *)VERSION, \
85 	(xmlChar *)ONE_DOT_O
86 static const xmlChar *xml_root[] = {
87 #include "data.def"
88 };
89 
90 #define	DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) (xmlChar *)TAG,
91 static const xmlChar* xmlTag[] = {
92 #include "data.def"
93 };
94 
95 #define	DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) TYPE,
96 static const char *xmlType[] = {
97 #include "data.def"
98 };
99 
100 #define	DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) ARG1,
101 static const int xmlArg1[] = {
102 #include "data.def"
103 };
104 
105 #define	DEF_XML_DATA(TAG, TYPE, ARG1, ARG2) ARG2,
106 static const int xmlArg2[] = {
107 #include "data.def"
108 };
109 
110 #define	DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) TYPE,
111 static const unsigned char xmlPropType[] = {
112 #include "data.def"
113 };
114 
115 #define	DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) (xmlChar *)NAME,
116 static const xmlChar *xmlPropName[] = {
117 #include "data.def"
118 };
119 
120 #define	DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) TAG,
121 static const int xmlPropTag[] = {
122 #include "data.def"
123 };
124 
125 #define	DEF_XML_PROP(INDEX, TYPE, NAME, TAG, ID) ID,
126 static const int xmlPropID[] = {
127 #include "data.def"
128 };
129 
130 #define	ARRAY_LENGTH(ARRAY) (sizeof (ARRAY) / sizeof (ARRAY[0]))
131 
132 /*
133  * ****************************************************************************
134  *
135  * get_index_by_name:
136  *	find the index in the global tables for the name of an attribute.
137  *
138  * name - the name of an attribute.
139  * return - index or -1 for error.
140  *
141  * ****************************************************************************
142  */
143 static int
144 get_index_by_name(
145 	const xmlChar *name
146 )
147 {
148 	int i;
149 	for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) {
150 		if (xmlStrEqual(xmlTag[i], name)) {
151 			return (i);
152 		}
153 	}
154 	return (-1);
155 }
156 
157 /*
158  * ****************************************************************************
159  *
160  * get_index_by_otype:
161  *	find the index in the global tables for the type of an object.
162  *
163  * name - the type of an object.
164  * return - index or -1 for error.
165  *
166  * ****************************************************************************
167  */
168 static int
169 get_index_by_otype(
170 	int otype
171 )
172 {
173 	int i;
174 	for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) {
175 		if (xmlArg1[i] == otype && xmlType[i][0] == 'o') {
176 			return (i);
177 		}
178 	}
179 	return (-1);
180 }
181 
182 /*
183  * ****************************************************************************
184  *
185  * get_index_by_tag:
186  *	find the index in the global tables for the tag of an attribute.
187  *
188  * name - the tag of an attribute.
189  * return - index or -1 for error.
190  *
191  * ****************************************************************************
192  */
193 static int
194 get_index_by_tag(
195 	int tag
196 )
197 {
198 	int i;
199 	for (i = 0; i < ARRAY_LENGTH(xmlTag); i++) {
200 		if (xmlArg1[i] == tag &&
201 		    xmlType[i][0] != 'o' &&
202 		    xmlType[i][0] != 'a') {
203 			return (i);
204 		}
205 	}
206 	return (-1);
207 }
208 
209 /*
210  * ****************************************************************************
211  *
212  * get_xml_doc:
213  *	open the xml file and assign the global xml doc if the xml file
214  *	is not opened, set the doc pointer with the opened xml file for
215  *	returnning.
216  *
217  * docp - the doc pointer for returning.
218  * return - error code.
219  *
220  * ****************************************************************************
221  */
222 static int
223 get_xml_doc(
224 	xmlDocPtr *docp
225 )
226 {
227 	int ec = 0;
228 
229 	if (xml_doc == NULL) {
230 		/* validate the xml file */
231 
232 		/* open the xml file */
233 		xml_doc = xmlParseFile(xml_file);
234 	}
235 
236 	*docp = xml_doc;
237 
238 	if (xml_doc == NULL) {
239 		ec = ISNS_RSP_INTERNAL_ERROR;
240 	}
241 
242 	return (ec);
243 }
244 
245 /*
246  * ****************************************************************************
247  *
248  * close_xml_doc:
249  *	close the global xml doc and ignore any changes that has been
250  *	made in it.
251  *
252  * ****************************************************************************
253  */
254 static void
255 close_xml_doc(
256 )
257 {
258 	if (xml_doc) {
259 		/* just close it */
260 		xmlFreeDoc(xml_doc);
261 		xml_doc = NULL;
262 	}
263 }
264 
265 /*
266  * ****************************************************************************
267  *
268  * convert_xml2attr:
269  *	convert a xml data to a TLV format isns attribute.
270  *
271  * tag - the tag of attribute.
272  * type - the data type of the xml data.
273  * value - the xml data.
274  * attr - TLV format attribute for returning.
275  * return - error code.
276  *
277  * ****************************************************************************
278  */
279 static int
280 convert_xml2attr(
281 	const int tag,
282 	const unsigned char type,
283 	xmlChar *value,
284 	isns_attr_t *attr
285 )
286 {
287 	uint32_t len;
288 	int ec = 0;
289 
290 	attr->tag = tag;
291 	switch (type) {
292 		case 'u':
293 			/* 4-bytes non-negative integer */
294 			attr->len = 4;
295 			attr->value.ui = atoi((const char *)value);
296 			break;
297 		case 's':
298 			/* literal string */
299 			len = strlen((char *)value);
300 			len += 4 - (len % 4);
301 			attr->len = len;
302 			attr->value.ptr = (uchar_t *)malloc(attr->len);
303 			if (attr->value.ptr != NULL) {
304 				(void) strcpy((char *)attr->value.ptr,
305 				    (char *)value);
306 			} else {
307 				ec = ISNS_RSP_INTERNAL_ERROR;
308 			}
309 			break;
310 		case 'p':
311 			/* IPv6 block data */
312 			attr->len = sizeof (in6_addr_t);
313 			attr->value.ip = (in6_addr_t *)malloc(attr->len);
314 			if (attr->value.ip != NULL) {
315 				(void) inet_pton(AF_INET6,
316 				    (char *)value,
317 				    attr->value.ip);
318 			} else {
319 				ec = ISNS_RSP_INTERNAL_ERROR;
320 			}
321 			break;
322 		default:
323 			break;
324 	}
325 
326 	return (ec);
327 }
328 
329 /*
330  * ****************************************************************************
331  *
332  * convert_attr2xml:
333  *	convert a TLV format isns attribute to xml node format.
334  *
335  * node - the xml node where the new node is being added to.
336  * attr - the TLV format attribute.
337  * name - the name of the attribute in xml node.
338  * type - the data type of the attribute.
339  * elm_flag - 0: adding a xml attlist.
340  *	      1: adding a xml child node.
341  *	      2: adding a previous sibling node.
342  *	      3: adding a xml content node.
343  *	      4: adding a xml attribute.
344  * return - xml node.
345  *
346  * ****************************************************************************
347  */
348 static xmlNodePtr
349 convert_attr2xml(
350 	xmlNodePtr node,
351 	const isns_attr_t *attr,
352 	const xmlChar *name,
353 	const char type,
354 	const int elm_flag
355 )
356 {
357 	xmlChar buff[INET6_ADDRSTRLEN + 1] = { 0 };
358 	xmlChar *value = NULL;
359 	xmlNodePtr child = NULL;
360 
361 	switch (type) {
362 		case 'u':
363 			/* 4-bytes non-negative integer */
364 			if (xmlStrPrintf(buff, sizeof (buff),
365 			    (const unsigned char *)"%u",
366 			    attr->value.ui) > 0) {
367 				value = (xmlChar *)&buff;
368 			}
369 			break;
370 		case 's':
371 			/* literal string */
372 			value = (xmlChar *)attr->value.ptr;
373 			break;
374 		case 'p':
375 			/* IPv6 block data */
376 			value = (xmlChar *)inet_ntop(AF_INET6,
377 			    (char *)attr->value.ip,
378 			    (char *)buff,
379 			    sizeof (buff));
380 			break;
381 		default:
382 			break;
383 	}
384 
385 	if (!value) {
386 		return (NULL);
387 	}
388 
389 	switch (elm_flag) {
390 		case 0: /* attlist */
391 			if (xmlSetProp(node, name, value)) {
392 				child = node;
393 			}
394 			break;
395 		case 1: /* child element */
396 			child = xmlNewChild(node, NULL, name, value);
397 			break;
398 		case 2: /* prev sibling element */
399 			child = xmlNewNode(NULL, name);
400 			if (child != NULL &&
401 			    xmlAddPrevSibling(node, child) == NULL) {
402 				xmlFreeNode(child);
403 				node = NULL;
404 			} else {
405 				node = child;
406 			}
407 			/* LINTED E_CASE_FALLTHRU */
408 		case 3: /* set content */
409 			if (node) {
410 				xmlNodeSetContent(node, value);
411 			}
412 			child = node;
413 			break;
414 		case 4: /* new attr value */
415 			if (xmlSetProp(node, name, value)) {
416 				child = node;
417 			}
418 			break;
419 		default:
420 			ASSERT(0);
421 			break;
422 	}
423 
424 	return (child);
425 }
426 
427 /*
428  * ****************************************************************************
429  *
430  * parse_xml_prop:
431  *	parse the properties of a xml node and convert them to the attributes
432  *	of an isns object, these xml properties are the UID attribute and
433  *	key attributes of the isns object.
434  *
435  * node - the xml node that contains the properties.
436  * obj - the isns object.
437  * i  - the index of the attribute in the global tables.
438  * return - error code.
439  *
440  * ****************************************************************************
441  */
442 static int
443 parse_xml_prop(
444 	xmlNodePtr node,
445 	isns_obj_t *obj,
446 	int i
447 )
448 {
449 	int ec = 0;
450 	const char *props = &xmlType[i][1];
451 	const xmlChar *prop_name;
452 	xmlChar *prop_value;
453 	unsigned char prop_type;
454 	int prop_tag;
455 	int prop_id;
456 	char prop;
457 	int j;
458 
459 	j = 0;
460 	prop = props[j ++];
461 	while (ec == 0 &&
462 	    prop >= 'a' && prop <= 'z') {
463 		prop -= 'a';
464 		prop_id = xmlPropID[prop];
465 		prop_tag = xmlPropTag[prop];
466 		prop_name = xmlPropName[prop];
467 		prop_type = xmlPropType[prop];
468 		prop_value = xmlGetProp(node, prop_name);
469 
470 		if (prop_value) {
471 			ec = convert_xml2attr(
472 			    prop_tag,
473 			    prop_type,
474 			    prop_value,
475 			    &(obj->attrs[prop_id]));
476 			xmlFree(prop_value);
477 		}
478 		prop = props[j ++];
479 	}
480 
481 	return (ec);
482 }
483 
484 /*
485  * ****************************************************************************
486  *
487  * parse_xml_attr:
488  *	parse a xml node and convert it to one isns object attribute.
489  *	this attribute is the non-key attribute of the isns object.
490  *
491  * node - the xml node.
492  * obj - the isns object.
493  * i  - the index of the attribute in the global tables.
494  * return - error code.
495  *
496  * ****************************************************************************
497  */
498 static int
499 parse_xml_attr(
500 	xmlNodePtr node,
501 	isns_obj_t *obj,
502 	int i
503 )
504 {
505 	int ec = 0;
506 	const unsigned char attr_type = xmlType[i][0];
507 	const int attr_tag = xmlArg1[i];
508 	const int attr_id = xmlArg2[i];
509 	xmlChar *attr_value;
510 
511 	attr_value = xmlNodeGetContent(node);
512 
513 	if (attr_value) {
514 		ec = convert_xml2attr(
515 		    attr_tag,
516 		    attr_type,
517 		    attr_value,
518 		    &(obj->attrs[attr_id]));
519 		xmlFree(attr_value);
520 	}
521 
522 	return (ec);
523 }
524 
525 /*
526  * ****************************************************************************
527  *
528  * parse_xml_obj:
529  *	parse one isns object from the xml doc.
530  *
531  * nodep - the pointer of the xml node for parsing.
532  * objp - the pointer of isns object for returning.
533  * return - error code.
534  *
535  * ****************************************************************************
536  */
537 static int
538 parse_xml_obj(
539 	xmlNodePtr *nodep,
540 	isns_obj_t **objp
541 )
542 {
543 	int ec = 0;
544 	int i, j;
545 
546 	xmlNodePtr node = *nodep;
547 	xmlNodePtr children;
548 
549 	isns_obj_t *obj = *objp;
550 
551 	while (node && ec == 0) {
552 		if (node->type == XML_ELEMENT_NODE) {
553 			children = node->children;
554 			i = get_index_by_name(node->name);
555 			ASSERT(i >= 0);
556 			j = xmlType[i][0];
557 			if (j == 'o' && obj == NULL) {
558 				obj = obj_calloc(xmlArg1[i]);
559 				if (obj == NULL) {
560 					ec = ISNS_RSP_INTERNAL_ERROR;
561 					break;
562 				}
563 				if ((ec = parse_xml_prop(node, obj, i)) == 0 &&
564 				    (children == NULL ||
565 				    (ec = parse_xml_obj(&children, &obj)) ==
566 				    0)) {
567 					if (children != NULL &&
568 					    children != node->children) {
569 						*nodep = children;
570 					}
571 					*objp = obj;
572 				} else {
573 					free_object(obj);
574 				}
575 				break;
576 				/* LINTED E_NOP_IF_STMT */
577 			} else if (j == 'o') {
578 			} else if (j != 0) {
579 				ASSERT(obj);
580 				if (children != NULL) {
581 					ec = parse_xml_attr(children, obj, i);
582 					*nodep = children;
583 				} else {
584 					/* assign a default value */
585 					*nodep = node;
586 				}
587 			} else {
588 				/* unknown xml node */
589 				break;
590 			}
591 			/* LINTED E_NOP_ELSE_STMT */
592 		} else {
593 			/* carry return or blank spaces, skip it */
594 		}
595 		node = node->next;
596 	}
597 
598 	return (ec);
599 }
600 
601 /*
602  * ****************************************************************************
603  *
604  * locate_xml_node:
605  *	locate the xml node from xml doc by matching the object UID.
606  *
607  * doc - the xml doc.
608  * otype - the matching object type.
609  * match_uid - the matching object UID.
610  * node - the pointer of matched xml node for returning.
611  * context - the xml context for matching process.
612  * result - the xml result for matching process.
613  * return - error code.
614  *
615  * ****************************************************************************
616  */
617 static int
618 locate_xml_node(
619 	xmlDocPtr doc,
620 	int otype,
621 	int match_uid,
622 	xmlNodePtr *node,
623 	xmlXPathContextPtr *context,
624 	xmlXPathObjectPtr *result
625 )
626 {
627 	int ec = 0;
628 
629 	xmlNodeSetPtr nodeset;
630 	xmlNodePtr curr;
631 	xmlChar expr[32] = { (xmlChar)'/', (xmlChar)'/', 0 };
632 
633 	char prop;
634 	const xmlChar *prop_name;
635 	xmlChar *prop_value;
636 	int uid;
637 
638 	int i, j;
639 
640 	*node = NULL;
641 
642 	i = get_index_by_otype(otype);
643 	ASSERT(i >= 0);
644 
645 	*context = xmlXPathNewContext(doc);
646 
647 	if (*context &&
648 	    xmlStrPrintf(&expr[2], 30, (const unsigned char *)"%s",
649 	    xmlTag[i]) != -1) {
650 		*result = xmlXPathEvalExpression(expr, *context);
651 		if (*result) {
652 			prop = xmlArg2[i] - 'a';
653 			prop_name = xmlPropName[prop];
654 			ASSERT(xmlPropType[prop] == 'u');
655 			nodeset = (*result)->nodesetval;
656 			for (j = 0;
657 			    nodeset && (j < nodeset->nodeNr);
658 			    j++) {
659 				curr = nodeset->nodeTab[j];
660 				prop_value = xmlGetProp(curr, prop_name);
661 				if (prop_value) {
662 					uid = atoi((const char *)prop_value);
663 					xmlFree(prop_value);
664 					if (uid == match_uid) {
665 						/* found it */
666 						*node = curr;
667 						return (ec);
668 					}
669 				}
670 			}
671 		} else {
672 			ec = ISNS_RSP_INTERNAL_ERROR;
673 		}
674 	} else {
675 		ec = ISNS_RSP_INTERNAL_ERROR;
676 	}
677 
678 	if (*result) {
679 		xmlXPathFreeObject(*result);
680 		*result = NULL;
681 	}
682 	if (*context) {
683 		xmlXPathFreeContext(*context);
684 		*context = NULL;
685 	}
686 
687 	return (ec);
688 }
689 
690 /*
691  * ****************************************************************************
692  *
693  * make_xml_node:
694  *	generate a xml node for presenting an isns object.
695  *
696  * obj - an isns object.
697  * return - the xml node.
698  *
699  * ****************************************************************************
700  */
701 static xmlNodePtr
702 make_xml_node(
703 	const isns_obj_t *obj
704 )
705 {
706 	const isns_attr_t *attr;
707 
708 	xmlNodePtr node;
709 	const char *props;
710 	char prop;
711 	const xmlChar *name;
712 	unsigned char type;
713 	int prop_id;
714 	int i, j;
715 
716 	i = get_index_by_otype(obj->type);
717 	ASSERT(i >= 0);
718 	node = xmlNewNode(NULL, xmlTag[i]);
719 	if (!node) {
720 		return (NULL);
721 	}
722 
723 	/* generate xml attributes of the node */
724 	props = &xmlType[i][1];
725 	prop = *(props ++);
726 	while (prop >= 'a' && prop <= 'z') {
727 		prop -= 'a';
728 		prop_id = xmlPropID[prop];
729 		name = xmlPropName[prop];
730 		type = xmlPropType[prop];
731 		attr = &obj->attrs[prop_id];
732 		if (!convert_attr2xml(node, attr, name, type, 0)) {
733 			xmlFreeNode(node);
734 			return (NULL);
735 		}
736 		/* attr->tag = 0; */
737 		prop = *(props ++);
738 	}
739 
740 	/* generate sub elements for isns attributes of the object */
741 	i = 0;
742 	while (i < NUM_OF_ATTRS[obj->type]) {
743 		attr = &obj->attrs[i ++];
744 		j = get_index_by_tag(attr->tag);
745 		if (j >= 0) {
746 			name = xmlTag[j];
747 			type = xmlType[j][0];
748 			if (!convert_attr2xml(node, attr, name, type, 1)) {
749 				xmlFreeNode(node);
750 				return (NULL);
751 			}
752 		}
753 	}
754 
755 	return (node);
756 }
757 
758 /*
759  * ****************************************************************************
760  *
761  * xml_init_data:
762  *	initialization of the xml data store.
763  *
764  * return - error code.
765  *
766  * ****************************************************************************
767  */
768 static int
769 xml_init_data(
770 )
771 {
772 #define	XML_PATH	"/etc/isns"
773 #define	XML_FILE_NAME	"/isnsdata.xml"
774 #define	XML_DOT_TMP	".tmp"
775 #define	XML_DOT_BAK	".bak"
776 
777 	int fd;
778 	xmlDocPtr doc;
779 	xmlNodePtr root;
780 
781 	int len;
782 	char *xml_path, *p = NULL;
783 
784 	char *cwd = NULL;
785 
786 	int has_bak = 0;
787 
788 	/* cannot reset the xml file when server is running */
789 	if (xml_file != NULL) {
790 		return (1);
791 	}
792 
793 	/* set the data store file name along with the backup */
794 	/* file name and temporary file name */
795 	len = strlen(data_store);
796 	if (len > 0) {
797 		xml_file = data_store;
798 		p = strdup(xml_file);
799 		xml_bak_file = (char *)malloc(len + 5);
800 		xml_tmp_file = (char *)malloc(len + 5);
801 		if (p != NULL &&
802 		    xml_bak_file != NULL &&
803 		    xml_tmp_file != NULL) {
804 			xml_path = dirname(p);
805 			(void) strcpy(xml_bak_file, xml_file);
806 			(void) strcat(xml_bak_file, XML_DOT_BAK);
807 			(void) strcpy(xml_tmp_file, xml_file);
808 			(void) strcat(xml_tmp_file, XML_DOT_TMP);
809 		} else {
810 			return (1);
811 		}
812 	} else {
813 		xml_path = XML_PATH;
814 		xml_file = XML_PATH XML_FILE_NAME;
815 		xml_bak_file = XML_PATH XML_FILE_NAME XML_DOT_BAK;
816 		xml_tmp_file = XML_PATH XML_FILE_NAME XML_DOT_TMP;
817 	}
818 
819 	/* save current working directory */
820 	cwd = getcwd(NULL, MAXPATHLEN);
821 	if (cwd == NULL) {
822 		return (1);
823 	}
824 	/* check access permission on data store directory */
825 	if (chdir(xml_path) != 0) {
826 		if (errno == ENOENT) {
827 			if (mkdir(xml_path, S_IRWXU) != 0 ||
828 			    chdir(xml_path) != 0) {
829 				return (1);
830 			}
831 		} else {
832 			return (1);
833 		}
834 	}
835 	/* go back to original working directory */
836 	(void) chdir(cwd);
837 	free(cwd);
838 	free(p);
839 
840 	/* do not keep blank spaces */
841 	(void) xmlKeepBlanksDefault(0);
842 
843 	/* remove the tmp file if it exists */
844 	if (access(xml_tmp_file, F_OK) == 0) {
845 		(void) remove(xml_tmp_file);
846 	}
847 
848 	/* test if we can write the bak file */
849 	fd = open(xml_bak_file, O_RDWR);
850 	if (fd == -1) {
851 		fd = open(xml_bak_file, O_RDWR | O_CREAT,
852 		    S_IRUSR | S_IWUSR);
853 		if (fd == -1) {
854 			return (1);
855 		} else {
856 			(void) close(fd);
857 			(void) remove(xml_bak_file);
858 		}
859 	} else {
860 		has_bak = 1;
861 		(void) close(fd);
862 	}
863 
864 	/* Test if we have the data store file, create an empty */
865 	/* data store if we do not have the data store file and */
866 	/* the backup data store. */
867 	fd = open(xml_file, O_RDWR);
868 	if (fd == -1) {
869 		if (has_bak == 0) {
870 			doc = xmlNewDoc(BAD_CAST "1.0");
871 			root = xmlNewNode(NULL, xml_root[0]);
872 			if (doc != NULL &&
873 			    root != NULL &&
874 			    xmlSetProp(root, xml_root[1], xml_root[2]) !=
875 			    NULL &&
876 			    xmlSetProp(root, xml_root[3], xml_root[4]) !=
877 			    NULL) {
878 				(void) xmlDocSetRootElement(doc, root);
879 				if (xmlSaveFormatFile(xml_file, doc, 1) == -1) {
880 					xmlFreeDoc(doc);
881 					return (-1);
882 				}
883 				xmlFreeDoc(doc);
884 			} else {
885 				if (doc != NULL) {
886 					xmlFreeDoc(doc);
887 				}
888 				if (root != NULL) {
889 					xmlFreeNode(root);
890 				}
891 				return (1);
892 			}
893 		} else {
894 			isnslog(LOG_WARNING, "get_xml_doc",
895 			    "initializing with backup data");
896 			if (rename(xml_bak_file, xml_file) != 0) {
897 				return (1);
898 			}
899 		}
900 	} else {
901 		(void) close(fd);
902 	}
903 
904 	return (0);
905 }
906 
907 /*
908  * ****************************************************************************
909  *
910  * xml_load_obj:
911  *	load an isns object from the xml data store.
912  *
913  * p - the pointer of current xml node.
914  * objp - the pointer of the object for returning.
915  * level - the direction of xml parsing for returning.
916  * return - error code.
917  *
918  * ****************************************************************************
919  */
920 static int
921 xml_load_obj(
922 	void **p,
923 	isns_obj_t **objp,
924 	uchar_t *level
925 )
926 {
927 	xmlDocPtr doc = NULL;
928 	xmlNodePtr node = (xmlNodePtr)*p;
929 	int ec = 0;
930 
931 	*objp = NULL;
932 
933 	if (node == NULL) {
934 		*level = '^';
935 		ec = get_xml_doc(&doc);
936 		if (doc == NULL) {
937 			return (ec);
938 		}
939 		node = xmlDocGetRootElement(doc);
940 		if (node != NULL) {
941 			node = node->children;
942 		}
943 	} else if (node->children != NULL) {
944 		*level = '>';
945 		node = node->children;
946 	} else if (node->next != NULL) {
947 		*level = 'v';
948 		node = node->next;
949 	} else {
950 		*level = 'v';
951 		while (node != NULL && node->next == NULL) {
952 			if (node->type == XML_ELEMENT_NODE) {
953 				*level = '<';
954 			}
955 			node = node->parent;
956 		}
957 		if (node != NULL) {
958 			node = node->next;
959 		}
960 	}
961 
962 	/* there is a node, parse it */
963 	if (node) {
964 		ec = parse_xml_obj(&node, objp);
965 		*p = (void *)node;
966 	}
967 
968 	if (ec == 0 && *objp != NULL) {
969 		ec = update_deref_obj(*objp);
970 		if (ec != 0) {
971 			free_object(*objp);
972 			*objp = NULL;
973 		}
974 	}
975 
976 	/* no object available, close the xml doc */
977 	if (*objp == NULL) {
978 		(void) close_xml_doc();
979 	}
980 
981 	return (ec);
982 }
983 
984 /*
985  * ****************************************************************************
986  *
987  * xml_add_obj:
988  *	add an isns object to the xml data store.
989  *
990  * obj - the object being added.
991  * return - error code.
992  *
993  * ****************************************************************************
994  */
995 static int
996 xml_add_obj(
997 	const isns_obj_t *obj
998 )
999 {
1000 	int ec = 0;
1001 
1002 	xmlDocPtr doc;
1003 	xmlXPathContextPtr context = NULL;
1004 	xmlXPathObjectPtr result = NULL;
1005 	xmlNodePtr node, prev;
1006 	xmlNodePtr candidate;
1007 
1008 	uint32_t puid, parent_type;
1009 
1010 	int i;
1011 
1012 	/* get the xml doc */
1013 	ec = get_xml_doc(&doc);
1014 	if (doc == NULL) {
1015 		goto add_done;
1016 	}
1017 
1018 	/* create the candidate node */
1019 	candidate = make_xml_node(obj);
1020 	if (candidate == NULL) {
1021 		ec = ISNS_RSP_INTERNAL_ERROR;
1022 		goto add_done;
1023 	}
1024 
1025 	/* locate the position */
1026 	parent_type = TYPE_OF_PARENT[obj->type];
1027 	if (parent_type > 0) {
1028 		puid = get_parent_uid(obj);
1029 		ec = locate_xml_node(doc, parent_type, puid,
1030 		    &node, &context, &result);
1031 	} else {
1032 		node = xmlDocGetRootElement(doc);
1033 	}
1034 
1035 	/* cannot locate the point for inserting the node */
1036 	if (node == NULL) {
1037 		xmlFreeNode(candidate);
1038 		ec = ISNS_RSP_INTERNAL_ERROR;
1039 		goto add_done;
1040 	}
1041 
1042 	/* add it with the apporiate child order */
1043 	if (node->children) {
1044 		node = node->children;
1045 		while (node) {
1046 			if (node->type == XML_ELEMENT_NODE) {
1047 				i = get_index_by_name(node->name);
1048 				ASSERT(i >= 0);
1049 				if (xmlType[i][0] == 'o' &&
1050 				    OBJ_DTD_ORDER[xmlArg1[i]] >=
1051 				    OBJ_DTD_ORDER[obj->type]) {
1052 					break;
1053 				}
1054 			}
1055 			prev = node;
1056 			node = node->next;
1057 		}
1058 		if (node == NULL) {
1059 			node = xmlAddNextSibling(prev, candidate);
1060 		} else {
1061 			node = xmlAddPrevSibling(node, candidate);
1062 		}
1063 	} else {
1064 		node = xmlAddChild(node, candidate);
1065 	}
1066 
1067 	if (node == NULL) {
1068 		/* Failed, free the candidate node. */
1069 		xmlFreeNode(candidate);
1070 		ec = ISNS_RSP_INTERNAL_ERROR;
1071 	}
1072 
1073 add_done:
1074 	if (result) {
1075 		xmlXPathFreeObject(result);
1076 	}
1077 	if (context) {
1078 		xmlXPathFreeContext(context);
1079 	}
1080 
1081 	return (ec);
1082 }
1083 
1084 /*
1085  * ****************************************************************************
1086  *
1087  * xml_modify_obj:
1088  *	modify an isns object in the xml data store.
1089  *
1090  * obj - the new object.
1091  * return - error code.
1092  *
1093  * ****************************************************************************
1094  */
1095 static int
1096 xml_modify_obj(
1097 	const isns_obj_t *obj
1098 )
1099 {
1100 	int ec = 0;
1101 	xmlDocPtr doc;
1102 	xmlXPathContextPtr context = NULL;
1103 	xmlXPathObjectPtr result = NULL;
1104 	xmlNodePtr node, child;
1105 	const char *props;
1106 	char prop;
1107 	int prop_id;
1108 	int prop_tag;
1109 	const xmlChar *name;
1110 	unsigned char type;
1111 	const isns_attr_t *attr;
1112 	int i, j, k;
1113 	int make_child;
1114 
1115 	/* get the doc pointer */
1116 	ec = get_xml_doc(&doc);
1117 	if (doc == NULL) {
1118 		return (ec);
1119 	}
1120 
1121 	/* locate the node for the object */
1122 	i = get_index_by_otype(obj->type);
1123 	ASSERT(i >= 0);
1124 	prop = xmlArg2[i] - 'a';
1125 	prop_id = xmlPropID[prop];
1126 	attr = &obj->attrs[prop_id];
1127 	ec = locate_xml_node(doc,
1128 	    obj->type,
1129 	    attr->value.ui,
1130 	    &node, &context, &result);
1131 
1132 	/* modify it */
1133 	if (node != NULL) {
1134 		props = &xmlType[i][1];
1135 		prop = *(props ++);
1136 		while (prop >= 'a' && prop <= 'z') {
1137 			prop -= 'a';
1138 			prop_id = xmlPropID[prop];
1139 			prop_tag = xmlPropTag[prop];
1140 			attr = &obj->attrs[prop_id];
1141 			/* no need to update the key attributes, skip it. */
1142 			/* btw, dd and dd-set names are non-key attributes. */
1143 			if (prop_tag == ISNS_DD_NAME_ATTR_ID ||
1144 			    prop_tag == ISNS_DD_SET_NAME_ATTR_ID) {
1145 				name = xmlPropName[prop];
1146 				type = xmlPropType[prop];
1147 				if (!convert_attr2xml(node,
1148 				    attr, name, type, 4)) {
1149 					ec = ISNS_RSP_INTERNAL_ERROR;
1150 					goto modify_done;
1151 				}
1152 			}
1153 			/* attr->tag = 0; */
1154 			prop = *(props ++);
1155 		}
1156 		/* set the child */
1157 		child = node->children;
1158 		if (child == NULL) {
1159 			make_child = 1;
1160 		} else {
1161 			make_child = 0;
1162 		}
1163 		for (i = 0; i < NUM_OF_ATTRS[obj->type]; i++) {
1164 			attr = &obj->attrs[i];
1165 			j = get_index_by_tag(attr->tag);
1166 			if (j < 0) {
1167 				continue;
1168 			}
1169 			name = xmlTag[j];
1170 			type = xmlType[j][0];
1171 			if (make_child == 1) {
1172 				/* make a child node */
1173 				if (!convert_attr2xml(node, attr,
1174 				    name, type, 1)) {
1175 					ec = ISNS_RSP_INTERNAL_ERROR;
1176 					goto modify_done;
1177 				}
1178 				continue;
1179 			}
1180 			while (child) {
1181 				if (child->type == XML_ELEMENT_NODE) {
1182 					k = get_index_by_name(child->name);
1183 					ASSERT(k >= 0);
1184 					if (xmlType[k][0] == 'o' ||
1185 					    xmlType[k][0] == 'a' ||
1186 					    xmlArg1[k] > attr->tag) {
1187 						if (!convert_attr2xml(child,
1188 						    attr, name, type, 2)) {
1189 							/* internal error */
1190 							ec = 11;
1191 							goto modify_done;
1192 						}
1193 						break;
1194 					} else if (xmlArg1[k] == attr->tag) {
1195 						/* replace content */
1196 						if (!convert_attr2xml(child,
1197 						    attr, name, type, 3)) {
1198 							/* internal error */
1199 							ec = 11;
1200 							goto modify_done;
1201 						}
1202 						break;
1203 					}
1204 				}
1205 				child = child->next;
1206 			}
1207 			if (child == NULL) {
1208 				/* make a child node */
1209 				if (!convert_attr2xml(node, attr,
1210 				    name, type, 1)) {
1211 					ec = ISNS_RSP_INTERNAL_ERROR;
1212 					goto modify_done;
1213 				}
1214 			}
1215 		}
1216 	} else {
1217 		/* This case is for registering a node which has */
1218 		/* membership in one or more non-default DD(s). */
1219 		ec = xml_add_obj(obj);
1220 	}
1221 
1222 modify_done:
1223 	if (result) {
1224 		xmlXPathFreeObject(result);
1225 	}
1226 	if (context) {
1227 		xmlXPathFreeContext(context);
1228 	}
1229 
1230 	return (ec);
1231 }
1232 
1233 /*
1234  * ****************************************************************************
1235  *
1236  * xml_delete_obj:
1237  *	delete an isns object from the xml data store.
1238  *
1239  * obj - the object being deleted.
1240  * return - error code.
1241  *
1242  * ****************************************************************************
1243  */
1244 static int
1245 xml_delete_obj(
1246 	const isns_obj_t *obj
1247 )
1248 {
1249 	int ec = 0;
1250 	xmlDocPtr doc;
1251 	xmlXPathContextPtr context = NULL;
1252 	xmlXPathObjectPtr result = NULL;
1253 	xmlNodePtr node;
1254 
1255 	isns_type_t otype;
1256 	uint32_t uid;
1257 
1258 	/* get the xml doc */
1259 	ec = get_xml_doc(&doc);
1260 	if (doc == NULL) {
1261 		return (ec);
1262 	}
1263 
1264 	otype = obj->type;
1265 #ifdef WRITE_DATA_ASYNC
1266 	/* it is a thin clone */
1267 	uid = obj->attrs[0].value.ui;
1268 #else
1269 	uid = get_obj_uid(obj);
1270 #endif
1271 
1272 	/* locate the object */
1273 	ec = locate_xml_node(doc,
1274 	    otype,
1275 	    uid,
1276 	    &node, &context, &result);
1277 
1278 	/* destroy it */
1279 	if (node) {
1280 		xmlUnlinkNode(node);
1281 		xmlFreeNode(node);
1282 	}
1283 
1284 	if (result) {
1285 		xmlXPathFreeObject(result);
1286 	}
1287 	if (context) {
1288 		xmlXPathFreeContext(context);
1289 	}
1290 
1291 	return (ec);
1292 }
1293 
1294 /*
1295  * ****************************************************************************
1296  *
1297  * xml_delete_assoc:
1298  *	delete a DD or DD-set membership from the xml data store.
1299  *
1300  * assoc - the membership being deleted.
1301  * return - error code.
1302  *
1303  * ****************************************************************************
1304  */
1305 static int
1306 xml_delete_assoc(
1307 	const isns_obj_t *assoc
1308 )
1309 {
1310 	int ec = 0;
1311 	xmlDocPtr doc;
1312 	xmlXPathContextPtr context = NULL;
1313 	xmlXPathObjectPtr result = NULL;
1314 	xmlNodePtr node;
1315 
1316 	uint32_t puid, parent_type;
1317 	uint32_t uid, match_uid;
1318 
1319 	char prop;
1320 	const xmlChar *prop_name;
1321 	xmlChar *prop_value;
1322 	int i;
1323 
1324 	/* get the xml doc */
1325 	ec = get_xml_doc(&doc);
1326 	if (doc == NULL) {
1327 		return (ec);
1328 	}
1329 
1330 	/* get the container object UID */
1331 	parent_type = TYPE_OF_PARENT[assoc->type];
1332 	ASSERT(parent_type != 0);
1333 	puid = get_parent_uid(assoc);
1334 	ASSERT(puid != 0);
1335 
1336 	/* get the member object UID */
1337 	i = get_index_by_otype(assoc->type);
1338 	prop = xmlArg2[i] - 'a';
1339 	prop_name = xmlPropName[prop];
1340 	match_uid = assoc->attrs[UID_ATTR_INDEX[assoc->type]].value.ui;
1341 
1342 	/* locate the container object */
1343 	ec = locate_xml_node(doc, parent_type, puid,
1344 	    &node, &context, &result);
1345 
1346 	/* get the membership nodes */
1347 	if (node != NULL) {
1348 		node = node->children;
1349 	}
1350 
1351 	/* get the matching membership node */
1352 	while (node) {
1353 		if (node->type == XML_ELEMENT_NODE) {
1354 			i = get_index_by_name(node->name);
1355 			ASSERT(i >= 0);
1356 			if (xmlType[i][0] == 'o' &&
1357 			    xmlArg1[i] == assoc->type) {
1358 				prop_value = xmlGetProp(node, prop_name);
1359 				if (prop_value) {
1360 					uid = atoi((const char *)prop_value);
1361 					xmlFree(prop_value);
1362 					if (uid == match_uid) {
1363 						break;
1364 					}
1365 				}
1366 			}
1367 		}
1368 		node = node->next;
1369 	}
1370 
1371 	/* destroy it */
1372 	if (node) {
1373 		xmlUnlinkNode(node);
1374 		xmlFreeNode(node);
1375 	}
1376 
1377 	if (result) {
1378 		xmlXPathFreeObject(result);
1379 	}
1380 	if (context) {
1381 		xmlXPathFreeContext(context);
1382 	}
1383 
1384 	return (ec);
1385 }
1386 
1387 /*
1388  * ****************************************************************************
1389  *
1390  * xml_update_commit:
1391  *	backup the current written file and commit all updates from
1392  *	the xml doc to the written file.
1393  *
1394  * return - error code.
1395  *
1396  * ****************************************************************************
1397  */
1398 static int
1399 xml_update_commit(
1400 )
1401 {
1402 	int ec = 0;
1403 
1404 	if (xml_doc) {
1405 		/* write to tmp file */
1406 		if (xmlSaveFormatFile(xml_tmp_file, xml_doc, 1) == -1 ||
1407 		    /* backup the current file */
1408 		    rename(xml_file, xml_bak_file) != 0 ||
1409 		    /* rename the tmp file to the current file */
1410 		    rename(xml_tmp_file, xml_file) != 0) {
1411 			/* failed saving file */
1412 			ec = ISNS_RSP_INTERNAL_ERROR;
1413 		}
1414 		/* close the xml_doc */
1415 		xmlFreeDoc(xml_doc);
1416 		xml_doc = NULL;
1417 	}
1418 
1419 	return (ec);
1420 }
1421 
1422 /*
1423  * ****************************************************************************
1424  *
1425  * xml_update_retreat:
1426  *	ignore all of updates in the xml doc.
1427  *
1428  * return - 0: always successful.
1429  *
1430  * ****************************************************************************
1431  */
1432 static int
1433 xml_update_retreat(
1434 )
1435 {
1436 	if (xml_doc) {
1437 		/* close the xml_doc */
1438 		xmlFreeDoc(xml_doc);
1439 		xml_doc = NULL;
1440 	}
1441 
1442 	return (0);
1443 }
1444