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