xref: /illumos-gate/usr/src/cmd/isns/isnsd/xml/data.c (revision bfed486ad8de8b8ebc6345a8e10accae08bf2f45)
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 2008 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 	/* test if we can write the tmp file */
844 	fd = open(xml_tmp_file, O_WRONLY | O_CREAT | O_EXCL,
845 	    S_IRUSR | S_IWUSR);
846 	if (fd == -1) {
847 		return (1);
848 	}
849 	(void) close(fd);
850 	(void) remove(xml_tmp_file);
851 
852 	/* test if we can write the bak file */
853 	fd = open(xml_bak_file, O_RDWR);
854 	if (fd == -1) {
855 		fd = open(xml_bak_file, O_RDWR | O_CREAT,
856 		    S_IRUSR | S_IWUSR);
857 		if (fd == -1) {
858 			return (1);
859 		} else {
860 			(void) close(fd);
861 			(void) remove(xml_bak_file);
862 		}
863 	} else {
864 		has_bak = 1;
865 		(void) close(fd);
866 	}
867 
868 	/* Test if we have the data store file, create an empty */
869 	/* data store if we do not have the data store file and */
870 	/* the backup data store. */
871 	fd = open(xml_file, O_RDWR);
872 	if (fd == -1) {
873 		if (has_bak == 0) {
874 			doc = xmlNewDoc(BAD_CAST "1.0");
875 			root = xmlNewNode(NULL, xml_root[0]);
876 			if (doc != NULL &&
877 			    root != NULL &&
878 			    xmlSetProp(root, xml_root[1], xml_root[2]) !=
879 			    NULL &&
880 			    xmlSetProp(root, xml_root[3], xml_root[4]) !=
881 			    NULL) {
882 				(void) xmlDocSetRootElement(doc, root);
883 				if (xmlSaveFormatFile(xml_file, doc, 1) == -1) {
884 					xmlFreeDoc(doc);
885 					return (-1);
886 				}
887 				xmlFreeDoc(doc);
888 			} else {
889 				if (doc != NULL) {
890 					xmlFreeDoc(doc);
891 				}
892 				if (root != NULL) {
893 					xmlFreeNode(root);
894 				}
895 				return (1);
896 			}
897 		} else {
898 			isnslog(LOG_WARNING, "get_xml_doc",
899 			    "initializing with backup data");
900 			if (rename(xml_bak_file, xml_file) != 0) {
901 				return (1);
902 			}
903 		}
904 	} else {
905 		(void) close(fd);
906 	}
907 
908 	return (0);
909 }
910 
911 /*
912  * ****************************************************************************
913  *
914  * xml_load_obj:
915  *	load an isns object from the xml data store.
916  *
917  * p - the pointer of current xml node.
918  * objp - the pointer of the object for returning.
919  * level - the direction of xml parsing for returning.
920  * return - error code.
921  *
922  * ****************************************************************************
923  */
924 static int
925 xml_load_obj(
926 	void **p,
927 	isns_obj_t **objp,
928 	uchar_t *level
929 )
930 {
931 	xmlDocPtr doc = NULL;
932 	xmlNodePtr node = (xmlNodePtr)*p;
933 	int ec = 0;
934 
935 	*objp = NULL;
936 
937 	if (node == NULL) {
938 		*level = '^';
939 		ec = get_xml_doc(&doc);
940 		if (doc == NULL) {
941 			return (ec);
942 		}
943 		node = xmlDocGetRootElement(doc);
944 		if (node != NULL) {
945 			node = node->children;
946 		}
947 	} else if (node->children != NULL) {
948 		*level = '>';
949 		node = node->children;
950 	} else if (node->next != NULL) {
951 		*level = 'v';
952 		node = node->next;
953 	} else {
954 		*level = 'v';
955 		while (node != NULL && node->next == NULL) {
956 			if (node->type == XML_ELEMENT_NODE) {
957 				*level = '<';
958 			}
959 			node = node->parent;
960 		}
961 		if (node != NULL) {
962 			node = node->next;
963 		}
964 	}
965 
966 	/* there is a node, parse it */
967 	if (node) {
968 		ec = parse_xml_obj(&node, objp);
969 		*p = (void *)node;
970 	}
971 
972 	if (ec == 0 && *objp != NULL) {
973 		ec = update_deref_obj(*objp);
974 		if (ec != 0) {
975 			free_object(*objp);
976 			*objp = NULL;
977 		}
978 	}
979 
980 	/* no object available, close the xml doc */
981 	if (*objp == NULL) {
982 		(void) close_xml_doc();
983 	}
984 
985 	return (ec);
986 }
987 
988 /*
989  * ****************************************************************************
990  *
991  * xml_add_obj:
992  *	add an isns object to the xml data store.
993  *
994  * obj - the object being added.
995  * return - error code.
996  *
997  * ****************************************************************************
998  */
999 static int
1000 xml_add_obj(
1001 	const isns_obj_t *obj
1002 )
1003 {
1004 	int ec = 0;
1005 
1006 	xmlDocPtr doc;
1007 	xmlXPathContextPtr context = NULL;
1008 	xmlXPathObjectPtr result = NULL;
1009 	xmlNodePtr node, prev;
1010 	xmlNodePtr candidate;
1011 
1012 	uint32_t puid, parent_type;
1013 
1014 	int i;
1015 
1016 	/* get the xml doc */
1017 	ec = get_xml_doc(&doc);
1018 	if (doc == NULL) {
1019 		goto add_done;
1020 	}
1021 
1022 	/* create the candidate node */
1023 	candidate = make_xml_node(obj);
1024 	if (candidate == NULL) {
1025 		ec = ISNS_RSP_INTERNAL_ERROR;
1026 		goto add_done;
1027 	}
1028 
1029 	/* locate the position */
1030 	parent_type = TYPE_OF_PARENT[obj->type];
1031 	if (parent_type > 0) {
1032 		puid = get_parent_uid(obj);
1033 		ec = locate_xml_node(doc, parent_type, puid,
1034 		    &node, &context, &result);
1035 	} else {
1036 		node = xmlDocGetRootElement(doc);
1037 	}
1038 
1039 	/* cannot locate the point for inserting the node */
1040 	if (node == NULL) {
1041 		xmlFreeNode(candidate);
1042 		ec = ISNS_RSP_INTERNAL_ERROR;
1043 		goto add_done;
1044 	}
1045 
1046 	/* add it with the apporiate child order */
1047 	if (node->children) {
1048 		node = node->children;
1049 		while (node) {
1050 			if (node->type == XML_ELEMENT_NODE) {
1051 				i = get_index_by_name(node->name);
1052 				ASSERT(i >= 0);
1053 				if (xmlType[i][0] == 'o' &&
1054 				    OBJ_DTD_ORDER[xmlArg1[i]] >=
1055 				    OBJ_DTD_ORDER[obj->type]) {
1056 					break;
1057 				}
1058 			}
1059 			prev = node;
1060 			node = node->next;
1061 		}
1062 		if (node == NULL) {
1063 			node = xmlAddNextSibling(prev, candidate);
1064 		} else {
1065 			node = xmlAddPrevSibling(node, candidate);
1066 		}
1067 	} else {
1068 		node = xmlAddChild(node, candidate);
1069 	}
1070 
1071 	if (node == NULL) {
1072 		/* Failed, free the candidate node. */
1073 		xmlFreeNode(candidate);
1074 		ec = ISNS_RSP_INTERNAL_ERROR;
1075 	}
1076 
1077 add_done:
1078 	if (result) {
1079 		xmlXPathFreeObject(result);
1080 	}
1081 	if (context) {
1082 		xmlXPathFreeContext(context);
1083 	}
1084 
1085 	return (ec);
1086 }
1087 
1088 /*
1089  * ****************************************************************************
1090  *
1091  * xml_modify_obj:
1092  *	modify an isns object in the xml data store.
1093  *
1094  * obj - the new object.
1095  * return - error code.
1096  *
1097  * ****************************************************************************
1098  */
1099 static int
1100 xml_modify_obj(
1101 	const isns_obj_t *obj
1102 )
1103 {
1104 	int ec = 0;
1105 	xmlDocPtr doc;
1106 	xmlXPathContextPtr context = NULL;
1107 	xmlXPathObjectPtr result = NULL;
1108 	xmlNodePtr node, child;
1109 	const char *props;
1110 	char prop;
1111 	int prop_id;
1112 	int prop_tag;
1113 	const xmlChar *name;
1114 	unsigned char type;
1115 	const isns_attr_t *attr;
1116 	int i, j, k;
1117 	int make_child;
1118 
1119 	/* get the doc pointer */
1120 	ec = get_xml_doc(&doc);
1121 	if (doc == NULL) {
1122 		return (ec);
1123 	}
1124 
1125 	/* locate the node for the object */
1126 	i = get_index_by_otype(obj->type);
1127 	ASSERT(i >= 0);
1128 	prop = xmlArg2[i] - 'a';
1129 	prop_id = xmlPropID[prop];
1130 	attr = &obj->attrs[prop_id];
1131 	ec = locate_xml_node(doc,
1132 	    obj->type,
1133 	    attr->value.ui,
1134 	    &node, &context, &result);
1135 
1136 	/* modify it */
1137 	if (node != NULL) {
1138 		props = &xmlType[i][1];
1139 		prop = *(props ++);
1140 		while (prop >= 'a' && prop <= 'z') {
1141 			prop -= 'a';
1142 			prop_id = xmlPropID[prop];
1143 			prop_tag = xmlPropTag[prop];
1144 			attr = &obj->attrs[prop_id];
1145 			/* no need to update the key attributes, skip it. */
1146 			/* btw, dd and dd-set names are non-key attributes. */
1147 			if (prop_tag == ISNS_DD_NAME_ATTR_ID ||
1148 			    prop_tag == ISNS_DD_SET_NAME_ATTR_ID) {
1149 				name = xmlPropName[prop];
1150 				type = xmlPropType[prop];
1151 				if (!convert_attr2xml(node,
1152 				    attr, name, type, 4)) {
1153 					ec = ISNS_RSP_INTERNAL_ERROR;
1154 					goto modify_done;
1155 				}
1156 			}
1157 			/* attr->tag = 0; */
1158 			prop = *(props ++);
1159 		}
1160 		/* set the child */
1161 		child = node->children;
1162 		if (child == NULL) {
1163 			make_child = 1;
1164 		} else {
1165 			make_child = 0;
1166 		}
1167 		for (i = 0; i < NUM_OF_ATTRS[obj->type]; i++) {
1168 			attr = &obj->attrs[i];
1169 			j = get_index_by_tag(attr->tag);
1170 			if (j < 0) {
1171 				continue;
1172 			}
1173 			name = xmlTag[j];
1174 			type = xmlType[j][0];
1175 			if (make_child == 1) {
1176 				/* make a child node */
1177 				if (!convert_attr2xml(node, attr,
1178 				    name, type, 1)) {
1179 					ec = ISNS_RSP_INTERNAL_ERROR;
1180 					goto modify_done;
1181 				}
1182 				continue;
1183 			}
1184 			while (child) {
1185 				if (child->type == XML_ELEMENT_NODE) {
1186 					k = get_index_by_name(child->name);
1187 					ASSERT(k >= 0);
1188 					if (xmlType[k][0] == 'o' ||
1189 					    xmlType[k][0] == 'a' ||
1190 					    xmlArg1[k] > attr->tag) {
1191 						if (!convert_attr2xml(child,
1192 						    attr, name, type, 2)) {
1193 							/* internal error */
1194 							ec = 11;
1195 							goto modify_done;
1196 						}
1197 						break;
1198 					} else if (xmlArg1[k] == attr->tag) {
1199 						/* replace content */
1200 						if (!convert_attr2xml(child,
1201 						    attr, name, type, 3)) {
1202 							/* internal error */
1203 							ec = 11;
1204 							goto modify_done;
1205 						}
1206 						break;
1207 					}
1208 				}
1209 				child = child->next;
1210 			}
1211 			if (child == NULL) {
1212 				/* make a child node */
1213 				if (!convert_attr2xml(node, attr,
1214 				    name, type, 1)) {
1215 					ec = ISNS_RSP_INTERNAL_ERROR;
1216 					goto modify_done;
1217 				}
1218 			}
1219 		}
1220 	} else {
1221 		/* This case is for registering a node which has */
1222 		/* membership in one or more non-default DD(s). */
1223 		ec = xml_add_obj(obj);
1224 	}
1225 
1226 modify_done:
1227 	if (result) {
1228 		xmlXPathFreeObject(result);
1229 	}
1230 	if (context) {
1231 		xmlXPathFreeContext(context);
1232 	}
1233 
1234 	return (ec);
1235 }
1236 
1237 /*
1238  * ****************************************************************************
1239  *
1240  * xml_delete_obj:
1241  *	delete an isns object from the xml data store.
1242  *
1243  * obj - the object being deleted.
1244  * return - error code.
1245  *
1246  * ****************************************************************************
1247  */
1248 static int
1249 xml_delete_obj(
1250 	const isns_obj_t *obj
1251 )
1252 {
1253 	int ec = 0;
1254 	xmlDocPtr doc;
1255 	xmlXPathContextPtr context = NULL;
1256 	xmlXPathObjectPtr result = NULL;
1257 	xmlNodePtr node;
1258 
1259 	isns_type_t otype;
1260 	uint32_t uid;
1261 
1262 	/* get the xml doc */
1263 	ec = get_xml_doc(&doc);
1264 	if (doc == NULL) {
1265 		return (ec);
1266 	}
1267 
1268 	otype = obj->type;
1269 #ifdef WRITE_DATA_ASYNC
1270 	/* it is a thin clone */
1271 	uid = obj->attrs[0].value.ui;
1272 #else
1273 	uid = get_obj_uid(obj);
1274 #endif
1275 
1276 	/* locate the object */
1277 	ec = locate_xml_node(doc,
1278 	    otype,
1279 	    uid,
1280 	    &node, &context, &result);
1281 
1282 	/* destroy it */
1283 	if (node) {
1284 		xmlUnlinkNode(node);
1285 		xmlFreeNode(node);
1286 	}
1287 
1288 	if (result) {
1289 		xmlXPathFreeObject(result);
1290 	}
1291 	if (context) {
1292 		xmlXPathFreeContext(context);
1293 	}
1294 
1295 	return (ec);
1296 }
1297 
1298 /*
1299  * ****************************************************************************
1300  *
1301  * xml_delete_assoc:
1302  *	delete a DD or DD-set membership from the xml data store.
1303  *
1304  * assoc - the membership being deleted.
1305  * return - error code.
1306  *
1307  * ****************************************************************************
1308  */
1309 static int
1310 xml_delete_assoc(
1311 	const isns_obj_t *assoc
1312 )
1313 {
1314 	int ec = 0;
1315 	xmlDocPtr doc;
1316 	xmlXPathContextPtr context = NULL;
1317 	xmlXPathObjectPtr result = NULL;
1318 	xmlNodePtr node;
1319 
1320 	uint32_t puid, parent_type;
1321 	uint32_t uid, match_uid;
1322 
1323 	char prop;
1324 	const xmlChar *prop_name;
1325 	xmlChar *prop_value;
1326 	int i;
1327 
1328 	/* get the xml doc */
1329 	ec = get_xml_doc(&doc);
1330 	if (doc == NULL) {
1331 		return (ec);
1332 	}
1333 
1334 	/* get the container object UID */
1335 	parent_type = TYPE_OF_PARENT[assoc->type];
1336 	ASSERT(parent_type != 0);
1337 	puid = get_parent_uid(assoc);
1338 	ASSERT(puid != 0);
1339 
1340 	/* get the member object UID */
1341 	i = get_index_by_otype(assoc->type);
1342 	prop = xmlArg2[i] - 'a';
1343 	prop_name = xmlPropName[prop];
1344 	match_uid = assoc->attrs[UID_ATTR_INDEX[assoc->type]].value.ui;
1345 
1346 	/* locate the container object */
1347 	ec = locate_xml_node(doc, parent_type, puid,
1348 	    &node, &context, &result);
1349 
1350 	/* get the membership nodes */
1351 	if (node != NULL) {
1352 		node = node->children;
1353 	}
1354 
1355 	/* get the matching membership node */
1356 	while (node) {
1357 		if (node->type == XML_ELEMENT_NODE) {
1358 			i = get_index_by_name(node->name);
1359 			ASSERT(i >= 0);
1360 			if (xmlType[i][0] == 'o' &&
1361 			    xmlArg1[i] == assoc->type) {
1362 				prop_value = xmlGetProp(node, prop_name);
1363 				if (prop_value) {
1364 					uid = atoi((const char *)prop_value);
1365 					xmlFree(prop_value);
1366 					if (uid == match_uid) {
1367 						break;
1368 					}
1369 				}
1370 			}
1371 		}
1372 		node = node->next;
1373 	}
1374 
1375 	/* destroy it */
1376 	if (node) {
1377 		xmlUnlinkNode(node);
1378 		xmlFreeNode(node);
1379 	}
1380 
1381 	if (result) {
1382 		xmlXPathFreeObject(result);
1383 	}
1384 	if (context) {
1385 		xmlXPathFreeContext(context);
1386 	}
1387 
1388 	return (ec);
1389 }
1390 
1391 /*
1392  * ****************************************************************************
1393  *
1394  * xml_update_commit:
1395  *	backup the current written file and commit all updates from
1396  *	the xml doc to the written file.
1397  *
1398  * return - error code.
1399  *
1400  * ****************************************************************************
1401  */
1402 static int
1403 xml_update_commit(
1404 )
1405 {
1406 	int ec = 0;
1407 
1408 	if (xml_doc) {
1409 		/* write to tmp file */
1410 		if (xmlSaveFormatFile(xml_tmp_file, xml_doc, 1) == -1 ||
1411 		    /* backup the current file */
1412 		    rename(xml_file, xml_bak_file) != 0 ||
1413 		    /* rename the tmp file to the current file */
1414 		    rename(xml_tmp_file, xml_file) != 0) {
1415 			/* failed saving file */
1416 			ec = ISNS_RSP_INTERNAL_ERROR;
1417 		}
1418 		/* close the xml_doc */
1419 		xmlFreeDoc(xml_doc);
1420 		xml_doc = NULL;
1421 	}
1422 
1423 	return (ec);
1424 }
1425 
1426 /*
1427  * ****************************************************************************
1428  *
1429  * xml_update_retreat:
1430  *	ignore all of updates in the xml doc.
1431  *
1432  * return - 0: always successful.
1433  *
1434  * ****************************************************************************
1435  */
1436 static int
1437 xml_update_retreat(
1438 )
1439 {
1440 	if (xml_doc) {
1441 		/* close the xml_doc */
1442 		xmlFreeDoc(xml_doc);
1443 		xml_doc = NULL;
1444 	}
1445 
1446 	return (0);
1447 }
1448