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