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