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