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