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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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