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