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