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