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 2008 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 /* test if we can write the tmp file */ 844 fd = open(xml_tmp_file, O_WRONLY | O_CREAT | O_EXCL, 845 S_IRUSR | S_IWUSR); 846 if (fd == -1) { 847 return (1); 848 } 849 (void) close(fd); 850 (void) remove(xml_tmp_file); 851 852 /* test if we can write the bak file */ 853 fd = open(xml_bak_file, O_RDWR); 854 if (fd == -1) { 855 fd = open(xml_bak_file, O_RDWR | O_CREAT, 856 S_IRUSR | S_IWUSR); 857 if (fd == -1) { 858 return (1); 859 } else { 860 (void) close(fd); 861 (void) remove(xml_bak_file); 862 } 863 } else { 864 has_bak = 1; 865 (void) close(fd); 866 } 867 868 /* Test if we have the data store file, create an empty */ 869 /* data store if we do not have the data store file and */ 870 /* the backup data store. */ 871 fd = open(xml_file, O_RDWR); 872 if (fd == -1) { 873 if (has_bak == 0) { 874 doc = xmlNewDoc(BAD_CAST "1.0"); 875 root = xmlNewNode(NULL, xml_root[0]); 876 if (doc != NULL && 877 root != NULL && 878 xmlSetProp(root, xml_root[1], xml_root[2]) != 879 NULL && 880 xmlSetProp(root, xml_root[3], xml_root[4]) != 881 NULL) { 882 (void) xmlDocSetRootElement(doc, root); 883 if (xmlSaveFormatFile(xml_file, doc, 1) == -1) { 884 xmlFreeDoc(doc); 885 return (-1); 886 } 887 xmlFreeDoc(doc); 888 } else { 889 if (doc != NULL) { 890 xmlFreeDoc(doc); 891 } 892 if (root != NULL) { 893 xmlFreeNode(root); 894 } 895 return (1); 896 } 897 } else { 898 isnslog(LOG_WARNING, "get_xml_doc", 899 "initializing with backup data"); 900 if (rename(xml_bak_file, xml_file) != 0) { 901 return (1); 902 } 903 } 904 } else { 905 (void) close(fd); 906 } 907 908 return (0); 909 } 910 911 /* 912 * **************************************************************************** 913 * 914 * xml_load_obj: 915 * load an isns object from the xml data store. 916 * 917 * p - the pointer of current xml node. 918 * objp - the pointer of the object for returning. 919 * level - the direction of xml parsing for returning. 920 * return - error code. 921 * 922 * **************************************************************************** 923 */ 924 static int 925 xml_load_obj( 926 void **p, 927 isns_obj_t **objp, 928 uchar_t *level 929 ) 930 { 931 xmlDocPtr doc = NULL; 932 xmlNodePtr node = (xmlNodePtr)*p; 933 int ec = 0; 934 935 *objp = NULL; 936 937 if (node == NULL) { 938 *level = '^'; 939 ec = get_xml_doc(&doc); 940 if (doc == NULL) { 941 return (ec); 942 } 943 node = xmlDocGetRootElement(doc); 944 if (node != NULL) { 945 node = node->children; 946 } 947 } else if (node->children != NULL) { 948 *level = '>'; 949 node = node->children; 950 } else if (node->next != NULL) { 951 *level = 'v'; 952 node = node->next; 953 } else { 954 *level = 'v'; 955 while (node != NULL && node->next == NULL) { 956 if (node->type == XML_ELEMENT_NODE) { 957 *level = '<'; 958 } 959 node = node->parent; 960 } 961 if (node != NULL) { 962 node = node->next; 963 } 964 } 965 966 /* there is a node, parse it */ 967 if (node) { 968 ec = parse_xml_obj(&node, objp); 969 *p = (void *)node; 970 } 971 972 if (ec == 0 && *objp != NULL) { 973 ec = update_deref_obj(*objp); 974 if (ec != 0) { 975 free_object(*objp); 976 *objp = NULL; 977 } 978 } 979 980 /* no object available, close the xml doc */ 981 if (*objp == NULL) { 982 (void) close_xml_doc(); 983 } 984 985 return (ec); 986 } 987 988 /* 989 * **************************************************************************** 990 * 991 * xml_add_obj: 992 * add an isns object to the xml data store. 993 * 994 * obj - the object being added. 995 * return - error code. 996 * 997 * **************************************************************************** 998 */ 999 static int 1000 xml_add_obj( 1001 const isns_obj_t *obj 1002 ) 1003 { 1004 int ec = 0; 1005 1006 xmlDocPtr doc; 1007 xmlXPathContextPtr context = NULL; 1008 xmlXPathObjectPtr result = NULL; 1009 xmlNodePtr node, prev; 1010 xmlNodePtr candidate; 1011 1012 uint32_t puid, parent_type; 1013 1014 int i; 1015 1016 /* get the xml doc */ 1017 ec = get_xml_doc(&doc); 1018 if (doc == NULL) { 1019 goto add_done; 1020 } 1021 1022 /* create the candidate node */ 1023 candidate = make_xml_node(obj); 1024 if (candidate == NULL) { 1025 ec = ISNS_RSP_INTERNAL_ERROR; 1026 goto add_done; 1027 } 1028 1029 /* locate the position */ 1030 parent_type = TYPE_OF_PARENT[obj->type]; 1031 if (parent_type > 0) { 1032 puid = get_parent_uid(obj); 1033 ec = locate_xml_node(doc, parent_type, puid, 1034 &node, &context, &result); 1035 } else { 1036 node = xmlDocGetRootElement(doc); 1037 } 1038 1039 /* cannot locate the point for inserting the node */ 1040 if (node == NULL) { 1041 xmlFreeNode(candidate); 1042 ec = ISNS_RSP_INTERNAL_ERROR; 1043 goto add_done; 1044 } 1045 1046 /* add it with the apporiate child order */ 1047 if (node->children) { 1048 node = node->children; 1049 while (node) { 1050 if (node->type == XML_ELEMENT_NODE) { 1051 i = get_index_by_name(node->name); 1052 ASSERT(i >= 0); 1053 if (xmlType[i][0] == 'o' && 1054 OBJ_DTD_ORDER[xmlArg1[i]] >= 1055 OBJ_DTD_ORDER[obj->type]) { 1056 break; 1057 } 1058 } 1059 prev = node; 1060 node = node->next; 1061 } 1062 if (node == NULL) { 1063 node = xmlAddNextSibling(prev, candidate); 1064 } else { 1065 node = xmlAddPrevSibling(node, candidate); 1066 } 1067 } else { 1068 node = xmlAddChild(node, candidate); 1069 } 1070 1071 if (node == NULL) { 1072 /* Failed, free the candidate node. */ 1073 xmlFreeNode(candidate); 1074 ec = ISNS_RSP_INTERNAL_ERROR; 1075 } 1076 1077 add_done: 1078 if (result) { 1079 xmlXPathFreeObject(result); 1080 } 1081 if (context) { 1082 xmlXPathFreeContext(context); 1083 } 1084 1085 return (ec); 1086 } 1087 1088 /* 1089 * **************************************************************************** 1090 * 1091 * xml_modify_obj: 1092 * modify an isns object in the xml data store. 1093 * 1094 * obj - the new object. 1095 * return - error code. 1096 * 1097 * **************************************************************************** 1098 */ 1099 static int 1100 xml_modify_obj( 1101 const isns_obj_t *obj 1102 ) 1103 { 1104 int ec = 0; 1105 xmlDocPtr doc; 1106 xmlXPathContextPtr context = NULL; 1107 xmlXPathObjectPtr result = NULL; 1108 xmlNodePtr node, child; 1109 const char *props; 1110 char prop; 1111 int prop_id; 1112 int prop_tag; 1113 const xmlChar *name; 1114 unsigned char type; 1115 const isns_attr_t *attr; 1116 int i, j, k; 1117 int make_child; 1118 1119 /* get the doc pointer */ 1120 ec = get_xml_doc(&doc); 1121 if (doc == NULL) { 1122 return (ec); 1123 } 1124 1125 /* locate the node for the object */ 1126 i = get_index_by_otype(obj->type); 1127 ASSERT(i >= 0); 1128 prop = xmlArg2[i] - 'a'; 1129 prop_id = xmlPropID[prop]; 1130 attr = &obj->attrs[prop_id]; 1131 ec = locate_xml_node(doc, 1132 obj->type, 1133 attr->value.ui, 1134 &node, &context, &result); 1135 1136 /* modify it */ 1137 if (node != NULL) { 1138 props = &xmlType[i][1]; 1139 prop = *(props ++); 1140 while (prop >= 'a' && prop <= 'z') { 1141 prop -= 'a'; 1142 prop_id = xmlPropID[prop]; 1143 prop_tag = xmlPropTag[prop]; 1144 attr = &obj->attrs[prop_id]; 1145 /* no need to update the key attributes, skip it. */ 1146 /* btw, dd and dd-set names are non-key attributes. */ 1147 if (prop_tag == ISNS_DD_NAME_ATTR_ID || 1148 prop_tag == ISNS_DD_SET_NAME_ATTR_ID) { 1149 name = xmlPropName[prop]; 1150 type = xmlPropType[prop]; 1151 if (!convert_attr2xml(node, 1152 attr, name, type, 4)) { 1153 ec = ISNS_RSP_INTERNAL_ERROR; 1154 goto modify_done; 1155 } 1156 } 1157 /* attr->tag = 0; */ 1158 prop = *(props ++); 1159 } 1160 /* set the child */ 1161 child = node->children; 1162 if (child == NULL) { 1163 make_child = 1; 1164 } else { 1165 make_child = 0; 1166 } 1167 for (i = 0; i < NUM_OF_ATTRS[obj->type]; i++) { 1168 attr = &obj->attrs[i]; 1169 j = get_index_by_tag(attr->tag); 1170 if (j < 0) { 1171 continue; 1172 } 1173 name = xmlTag[j]; 1174 type = xmlType[j][0]; 1175 if (make_child == 1) { 1176 /* make a child node */ 1177 if (!convert_attr2xml(node, attr, 1178 name, type, 1)) { 1179 ec = ISNS_RSP_INTERNAL_ERROR; 1180 goto modify_done; 1181 } 1182 continue; 1183 } 1184 while (child) { 1185 if (child->type == XML_ELEMENT_NODE) { 1186 k = get_index_by_name(child->name); 1187 ASSERT(k >= 0); 1188 if (xmlType[k][0] == 'o' || 1189 xmlType[k][0] == 'a' || 1190 xmlArg1[k] > attr->tag) { 1191 if (!convert_attr2xml(child, 1192 attr, name, type, 2)) { 1193 /* internal error */ 1194 ec = 11; 1195 goto modify_done; 1196 } 1197 break; 1198 } else if (xmlArg1[k] == attr->tag) { 1199 /* replace content */ 1200 if (!convert_attr2xml(child, 1201 attr, name, type, 3)) { 1202 /* internal error */ 1203 ec = 11; 1204 goto modify_done; 1205 } 1206 break; 1207 } 1208 } 1209 child = child->next; 1210 } 1211 if (child == NULL) { 1212 /* make a child node */ 1213 if (!convert_attr2xml(node, attr, 1214 name, type, 1)) { 1215 ec = ISNS_RSP_INTERNAL_ERROR; 1216 goto modify_done; 1217 } 1218 } 1219 } 1220 } else { 1221 /* This case is for registering a node which has */ 1222 /* membership in one or more non-default DD(s). */ 1223 ec = xml_add_obj(obj); 1224 } 1225 1226 modify_done: 1227 if (result) { 1228 xmlXPathFreeObject(result); 1229 } 1230 if (context) { 1231 xmlXPathFreeContext(context); 1232 } 1233 1234 return (ec); 1235 } 1236 1237 /* 1238 * **************************************************************************** 1239 * 1240 * xml_delete_obj: 1241 * delete an isns object from the xml data store. 1242 * 1243 * obj - the object being deleted. 1244 * return - error code. 1245 * 1246 * **************************************************************************** 1247 */ 1248 static int 1249 xml_delete_obj( 1250 const isns_obj_t *obj 1251 ) 1252 { 1253 int ec = 0; 1254 xmlDocPtr doc; 1255 xmlXPathContextPtr context = NULL; 1256 xmlXPathObjectPtr result = NULL; 1257 xmlNodePtr node; 1258 1259 isns_type_t otype; 1260 uint32_t uid; 1261 1262 /* get the xml doc */ 1263 ec = get_xml_doc(&doc); 1264 if (doc == NULL) { 1265 return (ec); 1266 } 1267 1268 otype = obj->type; 1269 #ifdef WRITE_DATA_ASYNC 1270 /* it is a thin clone */ 1271 uid = obj->attrs[0].value.ui; 1272 #else 1273 uid = get_obj_uid(obj); 1274 #endif 1275 1276 /* locate the object */ 1277 ec = locate_xml_node(doc, 1278 otype, 1279 uid, 1280 &node, &context, &result); 1281 1282 /* destroy it */ 1283 if (node) { 1284 xmlUnlinkNode(node); 1285 xmlFreeNode(node); 1286 } 1287 1288 if (result) { 1289 xmlXPathFreeObject(result); 1290 } 1291 if (context) { 1292 xmlXPathFreeContext(context); 1293 } 1294 1295 return (ec); 1296 } 1297 1298 /* 1299 * **************************************************************************** 1300 * 1301 * xml_delete_assoc: 1302 * delete a DD or DD-set membership from the xml data store. 1303 * 1304 * assoc - the membership being deleted. 1305 * return - error code. 1306 * 1307 * **************************************************************************** 1308 */ 1309 static int 1310 xml_delete_assoc( 1311 const isns_obj_t *assoc 1312 ) 1313 { 1314 int ec = 0; 1315 xmlDocPtr doc; 1316 xmlXPathContextPtr context = NULL; 1317 xmlXPathObjectPtr result = NULL; 1318 xmlNodePtr node; 1319 1320 uint32_t puid, parent_type; 1321 uint32_t uid, match_uid; 1322 1323 char prop; 1324 const xmlChar *prop_name; 1325 xmlChar *prop_value; 1326 int i; 1327 1328 /* get the xml doc */ 1329 ec = get_xml_doc(&doc); 1330 if (doc == NULL) { 1331 return (ec); 1332 } 1333 1334 /* get the container object UID */ 1335 parent_type = TYPE_OF_PARENT[assoc->type]; 1336 ASSERT(parent_type != 0); 1337 puid = get_parent_uid(assoc); 1338 ASSERT(puid != 0); 1339 1340 /* get the member object UID */ 1341 i = get_index_by_otype(assoc->type); 1342 prop = xmlArg2[i] - 'a'; 1343 prop_name = xmlPropName[prop]; 1344 match_uid = assoc->attrs[UID_ATTR_INDEX[assoc->type]].value.ui; 1345 1346 /* locate the container object */ 1347 ec = locate_xml_node(doc, parent_type, puid, 1348 &node, &context, &result); 1349 1350 /* get the membership nodes */ 1351 if (node != NULL) { 1352 node = node->children; 1353 } 1354 1355 /* get the matching membership node */ 1356 while (node) { 1357 if (node->type == XML_ELEMENT_NODE) { 1358 i = get_index_by_name(node->name); 1359 ASSERT(i >= 0); 1360 if (xmlType[i][0] == 'o' && 1361 xmlArg1[i] == assoc->type) { 1362 prop_value = xmlGetProp(node, prop_name); 1363 if (prop_value) { 1364 uid = atoi((const char *)prop_value); 1365 xmlFree(prop_value); 1366 if (uid == match_uid) { 1367 break; 1368 } 1369 } 1370 } 1371 } 1372 node = node->next; 1373 } 1374 1375 /* destroy it */ 1376 if (node) { 1377 xmlUnlinkNode(node); 1378 xmlFreeNode(node); 1379 } 1380 1381 if (result) { 1382 xmlXPathFreeObject(result); 1383 } 1384 if (context) { 1385 xmlXPathFreeContext(context); 1386 } 1387 1388 return (ec); 1389 } 1390 1391 /* 1392 * **************************************************************************** 1393 * 1394 * xml_update_commit: 1395 * backup the current written file and commit all updates from 1396 * the xml doc to the written file. 1397 * 1398 * return - error code. 1399 * 1400 * **************************************************************************** 1401 */ 1402 static int 1403 xml_update_commit( 1404 ) 1405 { 1406 int ec = 0; 1407 1408 if (xml_doc) { 1409 /* write to tmp file */ 1410 if (xmlSaveFormatFile(xml_tmp_file, xml_doc, 1) == -1 || 1411 /* backup the current file */ 1412 rename(xml_file, xml_bak_file) != 0 || 1413 /* rename the tmp file to the current file */ 1414 rename(xml_tmp_file, xml_file) != 0) { 1415 /* failed saving file */ 1416 ec = ISNS_RSP_INTERNAL_ERROR; 1417 } 1418 /* close the xml_doc */ 1419 xmlFreeDoc(xml_doc); 1420 xml_doc = NULL; 1421 } 1422 1423 return (ec); 1424 } 1425 1426 /* 1427 * **************************************************************************** 1428 * 1429 * xml_update_retreat: 1430 * ignore all of updates in the xml doc. 1431 * 1432 * return - 0: always successful. 1433 * 1434 * **************************************************************************** 1435 */ 1436 static int 1437 xml_update_retreat( 1438 ) 1439 { 1440 if (xml_doc) { 1441 /* close the xml_doc */ 1442 xmlFreeDoc(xml_doc); 1443 xml_doc = NULL; 1444 } 1445 1446 return (0); 1447 } 1448