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