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