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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <limits.h> 29 #include <stdlib.h> 30 #include <stdio.h> 31 #include <string.h> 32 #include <thread.h> 33 #include <time.h> 34 #include <unistd.h> 35 36 #include <sys/mman.h> 37 #include <sys/stat.h> 38 #include <sys/time.h> 39 #include <sys/types.h> 40 #include <sys/utsname.h> 41 42 #include <libxml/debugXML.h> 43 #include <libxml/parser.h> 44 #include <libxml/tree.h> 45 #include <libxml/xmlerror.h> 46 #include <libxml/xpath.h> 47 #include <libxml/xmlmemory.h> 48 49 #include <pool.h> 50 #include "pool_internal.h" 51 #include "pool_impl.h" 52 #include "pool_xml_impl.h" 53 54 /* 55 * libpool XML Manipulation Routines 56 * 57 * pool_xml.c implements the XML manipulation routines used by the libpool 58 * XML datastore. The functions are grouped into the following logical areas 59 * - Result Sets 60 * The XPath API is used to search the XML document represented by a 61 * configuration. The results of XPath queries are represented through 62 * pool_result_set_t structures as part of the abstraction of the datastore 63 * representation. (see pool.c comment for more details) 64 * 65 * - Property Manipulation 66 * Validated XML (XML associated with a DTD) does not allow the introduction 67 * of attributes which are not recognised by the DTD. This is a limitation 68 * since we want to allow libpool to associate an arbitrary number of 69 * properties with an element. The property manipulation code overcomes this 70 * limitation by allowing property sub-elements to be created and manipulated 71 * through a single API so that they are indistinguishable from attributes 72 * to the libpool user. 73 * 74 * - XML Element/Attribute Manipulation 75 * These routines manipulate XML elements and attributes and are the routines 76 * which interact most directly with libxml. 77 * 78 * - File Processing/IO 79 * Since libpool must present its data in a consistent fashion, we have to 80 * implement file locking above libxml. These routines allow us to lock files 81 * during processing and maintain data integrity between processes. Note 82 * that locks are at the process scope and are advisory (see fcntl). 83 * 84 * - Utilities 85 * Sundry utility functions that aren't easily categorised. 86 */ 87 88 #define MAX_PROP_SIZE 1024 /* Size of property buffer */ 89 /* 90 * The PAGE_READ_SIZE value is used to determine the size of the input buffer 91 * used to parse XML files. 92 */ 93 #define PAGE_READ_SIZE 8192 94 #define ELEM_TYPE_COUNT 6 /* Count of Element types */ 95 96 typedef struct dtype_tbl 97 { 98 xmlChar *dt_name; 99 int dt_type; 100 } dtype_tbl_t; 101 102 typedef struct elem_type_tbl 103 { 104 xmlChar *ett_elem; 105 dtype_tbl_t (*ett_dtype)[]; 106 } elem_type_tbl_t; 107 108 extern int xmlDoValidityCheckingDefaultValue; 109 110 /* 111 * The _xml_lock is used to lock the state of libpool during 112 * xml initialisation operations. 113 */ 114 static mutex_t _xml_lock; 115 116 const char *element_class_tags[] = { 117 "any", 118 "system", 119 "pool", 120 "res_comp", 121 "res_agg", 122 "comp", 123 NULL 124 }; 125 126 static const char *data_type_tags[] = { 127 "uint", 128 "int", 129 "float", 130 "boolean", 131 "string" 132 }; 133 134 const char *dtd_location = "file:///usr/share/lib/xml/dtd/rm_pool.dtd.1"; 135 136 static elem_type_tbl_t elem_tbl[ELEM_TYPE_COUNT] = {0}; 137 138 /* libpool initialisation indicator */ 139 static int _libpool_xml_initialised = PO_FALSE; 140 141 /* 142 * Utility functions 143 */ 144 /* 145 * Those functions which are not static are shared with pool_kernel.c 146 * They provide the required XML support for exporting a kernel 147 * configuration as an XML document. 148 */ 149 void xml_init(void); 150 static int create_shadow(xmlNodePtr node); 151 static int pool_xml_free_doc(pool_conf_t *conf); 152 static int prop_sort(const void *a, const void *b); 153 static int dtd_exists(const char *path); 154 static void build_dtype_accelerator(void); 155 static dtype_tbl_t (*build_dtype_tbl(const xmlChar *rawdata))[]; 156 static int get_fast_dtype(xmlNodePtr node, xmlChar *name); 157 static int pool_assoc_default_resource_type(pool_t *, 158 pool_resource_elem_class_t); 159 160 /* 161 * XML Data access and navigation APIs 162 */ 163 static int pool_build_xpath_buf(pool_xml_connection_t *, const pool_elem_t *, 164 pool_elem_class_t, pool_value_t **, char_buf_t *, int); 165 /* 166 * SHARED WITH pool_kernel.c for XML export support 167 */ 168 xmlNodePtr node_create(xmlNodePtr parent, const xmlChar *name); 169 static xmlNodePtr node_create_with_id(xmlNodePtr parent, const xmlChar *name); 170 171 /* Configuration */ 172 static int pool_xml_close(pool_conf_t *); 173 static int pool_xml_validate(const pool_conf_t *, pool_valid_level_t); 174 static int pool_xml_commit(pool_conf_t *conf); 175 static int pool_xml_export(const pool_conf_t *conf, const char *location, 176 pool_export_format_t fmt); 177 static int pool_xml_rollback(pool_conf_t *conf); 178 static pool_result_set_t *pool_xml_exec_query(const pool_conf_t *conf, 179 const pool_elem_t *src, const char *src_attr, 180 pool_elem_class_t classes, pool_value_t **props); 181 static int pool_xml_remove(pool_conf_t *conf); 182 static int pool_xml_res_transfer(pool_resource_t *, pool_resource_t *, 183 uint64_t); 184 static int pool_xml_res_xtransfer(pool_resource_t *, pool_resource_t *, 185 pool_component_t **); 186 187 /* Connections */ 188 static void pool_xml_connection_free(pool_xml_connection_t *prov); 189 190 /* Result Sets */ 191 static pool_xml_result_set_t *pool_xml_result_set_alloc(const pool_conf_t *); 192 static void pool_xml_result_set_free(pool_xml_result_set_t *rs); 193 static pool_elem_t *pool_xml_rs_next(pool_result_set_t *set); 194 static pool_elem_t *pool_xml_rs_prev(pool_result_set_t *set); 195 static pool_elem_t *pool_xml_rs_first(pool_result_set_t *set); 196 static pool_elem_t *pool_xml_rs_last(pool_result_set_t *set); 197 static int pool_xml_rs_set_index(pool_result_set_t *set, int index); 198 static int pool_xml_rs_get_index(pool_result_set_t *set); 199 static int pool_xml_rs_count(pool_result_set_t *set); 200 static int pool_xml_rs_close(pool_result_set_t *set); 201 202 /* Element (and sub-type) */ 203 static void pool_xml_elem_init(pool_conf_t *conf, pool_xml_elem_t *elem, 204 pool_elem_class_t, pool_resource_elem_class_t, pool_component_elem_class_t); 205 static int pool_xml_elem_wrap(xmlNodePtr node, pool_elem_class_t class, 206 pool_resource_elem_class_t, pool_component_elem_class_t); 207 static pool_elem_t *pool_xml_elem_create(pool_conf_t *, pool_elem_class_t, 208 pool_resource_elem_class_t, pool_component_elem_class_t); 209 static int pool_xml_elem_remove(pool_elem_t *pe); 210 static int pool_xml_set_container(pool_elem_t *, pool_elem_t *); 211 static pool_elem_t *pool_xml_get_container(const pool_elem_t *); 212 213 /* 214 * Pool element specific 215 */ 216 static int pool_xml_pool_associate(pool_t *, const pool_resource_t *); 217 static int pool_xml_pool_dissociate(pool_t *, const pool_resource_t *); 218 219 /* 220 * Resource elements specific 221 */ 222 static int pool_xml_resource_is_system(const pool_resource_t *); 223 static int pool_xml_resource_can_associate(const pool_resource_t *); 224 225 /* Properties */ 226 static pool_value_class_t pool_xml_get_property(const pool_elem_t *, 227 const char *, pool_value_t *); 228 static int pool_xml_put_property(pool_elem_t *, const char *, 229 const pool_value_t *); 230 static int pool_xml_rm_property(pool_elem_t *, const char *); 231 static xmlNodePtr property_create(xmlNodePtr, const char *, 232 pool_value_class_t); 233 234 /* Internal Attribute/Property manipulation */ 235 static int pool_is_xml_attr(xmlDocPtr, const char *, const char *); 236 static pool_value_class_t pool_xml_get_attr(xmlNodePtr node, xmlChar *name, 237 pool_value_t *value); 238 int pool_xml_set_attr(xmlNodePtr node, xmlChar *name, 239 const pool_value_t *value); 240 static pool_value_class_t pool_xml_get_prop(xmlNodePtr node, xmlChar *name, 241 pool_value_t *value); 242 int pool_xml_set_prop(xmlNodePtr node, xmlChar *name, 243 const pool_value_t *value); 244 static pool_value_t **pool_xml_get_properties(const pool_elem_t *, uint_t *); 245 /* XML Error handling */ 246 void pool_error_func(void *ctx, const char *msg, ...); 247 248 /* XML File Input Processing */ 249 static int pool_xml_open_file(pool_conf_t *conf); 250 static int pool_xml_parse_document(pool_conf_t *); 251 252 /* 253 * Initialise this module 254 */ 255 void 256 xml_init() 257 { 258 (void) mutex_lock(&_xml_lock); 259 if (_libpool_xml_initialised == PO_TRUE) { 260 (void) mutex_unlock(&_xml_lock); 261 return; 262 } 263 xmlInitParser(); 264 265 /* 266 * DTD validation, with line numbers. 267 */ 268 (void) xmlLineNumbersDefault(1); 269 xmlLoadExtDtdDefaultValue |= XML_DETECT_IDS; 270 xmlDoValidityCheckingDefaultValue = 1; 271 /* Try to improve indentation and readability */ 272 (void) xmlKeepBlanksDefault(0); 273 /* Send all XML errors to our debug handler */ 274 xmlSetGenericErrorFunc(NULL, pool_error_func); 275 /* Load up DTD element a-dtype data to improve performance */ 276 build_dtype_accelerator(); 277 _libpool_xml_initialised = PO_TRUE; 278 (void) mutex_unlock(&_xml_lock); 279 } 280 281 /* 282 * Get the next ID for this configuration 283 */ 284 static int 285 get_unique_id(xmlNodePtr node, char *id) 286 { 287 pool_value_t val = POOL_VALUE_INITIALIZER; 288 uint64_t nid = 0; 289 if (node->doc->_private) { 290 if (pool_get_ns_property( 291 pool_conf_to_elem((pool_conf_t *)node->doc->_private), 292 "_next_id", &val) == POC_UINT) 293 (void) pool_value_get_uint64(&val, &nid); 294 } 295 if (snprintf(id, KEY_BUFFER_SIZE, "id_%llx", nid) > KEY_BUFFER_SIZE) { 296 pool_seterror(POE_SYSTEM); 297 return (PO_FAIL); 298 } 299 pool_value_set_uint64(&val, ++nid); 300 return (pool_put_ns_property( 301 pool_conf_to_elem((pool_conf_t *)node->doc->_private), "_next_id", 302 &val)); 303 } 304 305 /* Document building functions */ 306 307 /* 308 * node_create() creates a child node of type name of the supplied parent in 309 * the supplied document. If the parent or document is NULL, create the node 310 * but do not associate it with a parent or document. 311 */ 312 xmlNodePtr 313 node_create(xmlNodePtr parent, const xmlChar *name) 314 { 315 xmlNodePtr node; 316 317 if (parent == NULL) 318 node = xmlNewNode(NULL, name); 319 else 320 node = xmlNewChild(parent, NULL, name, NULL); 321 return (node); 322 } 323 324 /* 325 * node_create_with_id() creates a child node of type name of the supplied 326 * parent with the ref_id generated by get_unique_id(). Actual node creation 327 * is performed by node_create() and this function just sets the ref_id 328 * property to the value of the id. 329 */ 330 static xmlNodePtr 331 node_create_with_id(xmlNodePtr parent, const xmlChar *name) 332 { 333 char id[KEY_BUFFER_SIZE]; /* Must be big enough for key below */ 334 xmlNodePtr node = node_create(parent, name); 335 if (node != NULL) { 336 if (get_unique_id(node, id) != PO_SUCCESS) { 337 xmlUnlinkNode(node); 338 xmlFreeNode(node); /* recurses all children */ 339 pool_seterror(POE_DATASTORE); 340 return (NULL); 341 } 342 if (xmlSetProp(node, BAD_CAST c_ref_id, BAD_CAST id) == NULL) { 343 xmlUnlinkNode(node); 344 xmlFreeNode(node); /* recurses all children */ 345 pool_seterror(POE_DATASTORE); 346 return (NULL); 347 } 348 } 349 return (node); 350 } 351 352 /* Supporting Data Conversion Routines */ 353 354 /* XML Parser Utility Functions */ 355 356 /* 357 * Handler for XML Errors. Called by libxml at libxml Error. 358 */ 359 /*ARGSUSED*/ 360 void 361 pool_error_func(void *ctx, const char *msg, ...) 362 { 363 va_list ap; 364 365 va_start(ap, msg); 366 do_dprintf(msg, ap); 367 va_end(ap); 368 } 369 370 /* 371 * Free the shadowed elements from within the supplied document and then 372 * free the document. This function should always be called when freeing 373 * a pool document to ensure that all "shadow" resources are reclaimed. 374 * Returns PO_SUCCESS/PO_FAIL 375 */ 376 static int 377 pool_xml_free_doc(pool_conf_t *conf) 378 { 379 /* Only do any of this if there is a document */ 380 if (((pool_xml_connection_t *)conf->pc_prov)->pxc_doc != NULL) { 381 pool_elem_t *pe; 382 pool_result_set_t *rs; 383 /* Delete all the "shadowed" children of the doc */ 384 rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_ANY, NULL); 385 if (rs == NULL) { 386 pool_seterror(POE_INVALID_CONF); 387 return (PO_FAIL); 388 } 389 for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) { 390 /* 391 * Work out the element type and free the elem 392 */ 393 free(pe); 394 } 395 (void) pool_rs_close(rs); 396 xmlFreeDoc(((pool_xml_connection_t *)conf->pc_prov)->pxc_doc); 397 } 398 ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc = NULL; 399 return (PO_SUCCESS); 400 } 401 402 /* 403 * Remove an element from the document. Note that only three types of elements 404 * can be removed, res, comp and pools. comp are moved around to the 405 * default res when a res is deleted. 406 * Returns PO_SUCCESS/PO_FAIL 407 */ 408 static int 409 pool_xml_elem_remove(pool_elem_t *pe) 410 { 411 pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; 412 413 /* 414 * You can only destroy three elements: pools, resources and 415 * components. 416 */ 417 switch (pe->pe_class) { 418 case PEC_POOL: 419 case PEC_RES_COMP: 420 case PEC_RES_AGG: 421 case PEC_COMP: 422 if (pxe->pxe_node) { 423 xmlUnlinkNode(pxe->pxe_node); 424 xmlFreeNode(pxe->pxe_node); /* recurses all children */ 425 } 426 free(pxe); 427 break; 428 default: 429 break; 430 } 431 return (PO_SUCCESS); 432 } 433 434 /* 435 * Create a property element. 436 */ 437 static xmlNodePtr 438 property_create(xmlNodePtr parent, const char *name, pool_value_class_t type) 439 { 440 441 xmlNodePtr element; 442 pool_value_t val = POOL_VALUE_INITIALIZER; 443 444 if ((element = node_create(parent, BAD_CAST "property")) == NULL) { 445 pool_seterror(POE_DATASTORE); 446 return (NULL); 447 } 448 if (pool_value_set_string(&val, name) != PO_SUCCESS) { 449 xmlFree(element); 450 return (NULL); 451 } 452 (void) pool_xml_set_attr(element, BAD_CAST c_name, &val); 453 if (pool_value_set_string(&val, data_type_tags[type]) != PO_SUCCESS) { 454 xmlFree(element); 455 return (NULL); 456 } 457 (void) pool_xml_set_attr(element, BAD_CAST c_type, &val); 458 return (element); 459 } 460 461 /* 462 * External clients need to be able to put/get properties and this is the 463 * way to do it. 464 * This function is an interceptor, since it will *always* try to manipulate 465 * an attribute first. If the attribute doesn't exist, then it will treat 466 * the request as a property request. 467 */ 468 static pool_value_class_t 469 pool_xml_get_property(const pool_elem_t *pe, const char *name, 470 pool_value_t *val) 471 { 472 pool_value_class_t type; 473 pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; 474 475 /* 476 * "type" is a special attribute which is not visible ever outside of 477 * libpool. Use the specific type accessor function. 478 */ 479 if (strcmp(name, c_type) == 0) { 480 return (pool_xml_get_attr(pxe->pxe_node, BAD_CAST name, 481 val)); 482 } 483 if (is_ns_property(pe, name) != NULL) { /* in ns */ 484 if ((type = pool_xml_get_attr(pxe->pxe_node, 485 BAD_CAST property_name_minus_ns(pe, name), val)) 486 == POC_INVAL) 487 return (pool_xml_get_prop(pxe->pxe_node, BAD_CAST name, 488 val)); 489 } else 490 return (pool_xml_get_prop(pxe->pxe_node, BAD_CAST name, val)); 491 492 return (type); 493 } 494 495 /* 496 * Put a property on an element. Check if the property is an attribute, 497 * if it is update that value. If not add a property element. 498 * 499 * There are three possible conditions here: 500 * - the name is a ns 501 * - the name is an attribute 502 * - the name isn't an attribute 503 * - the name is not a ns 504 * Returns PO_SUCCESS/PO_FAIL 505 */ 506 static int 507 pool_xml_put_property(pool_elem_t *pe, const char *name, 508 const pool_value_t *val) 509 { 510 pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; 511 512 /* 513 * "type" is a special attribute which is not visible ever outside of 514 * libpool. Use the specific type accessor function. 515 */ 516 if (strcmp(name, c_type) == 0) { 517 return (pool_xml_set_attr(pxe->pxe_node, BAD_CAST name, 518 val)); 519 } 520 if (is_ns_property(pe, name) != NULL) { /* in ns */ 521 if (pool_xml_set_attr(pxe->pxe_node, 522 BAD_CAST property_name_minus_ns(pe, name), val) == PO_FAIL) 523 return (pool_xml_set_prop(pxe->pxe_node, BAD_CAST name, 524 val)); 525 } else 526 return (pool_xml_set_prop(pxe->pxe_node, BAD_CAST name, val)); 527 return (PO_SUCCESS); 528 } 529 530 /* 531 * Remove a property from an element. Check if the property is an attribute, 532 * if it is fail. Otherwise remove the property subelement. 533 * Returns PO_SUCCESS/PO_FAIL 534 */ 535 static int 536 pool_xml_rm_property(pool_elem_t *pe, const char *name) 537 { 538 pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; 539 xmlXPathContextPtr ctx; 540 xmlXPathObjectPtr path; 541 char buf[MAX_PROP_SIZE]; 542 int ret; 543 544 if (xmlHasProp(pxe->pxe_node, BAD_CAST name) != NULL) { 545 pool_seterror(POE_BADPARAM); 546 return (PO_FAIL); 547 } 548 549 /* use xpath to find the node with the appropriate value for name */ 550 (void) snprintf(buf, sizeof (buf), "property[@name=\"%s\"]", name); 551 if ((ctx = xmlXPathNewContext(pxe->pxe_node->doc)) == NULL) { 552 pool_seterror(POE_PUTPROP); 553 return (PO_FAIL); 554 } 555 ctx->node = pxe->pxe_node; 556 path = xmlXPathEval(BAD_CAST buf, ctx); 557 558 if (path && (path->type == XPATH_NODESET) && 559 (path->nodesetval->nodeNr == 1)) { 560 xmlUnlinkNode(path->nodesetval->nodeTab[0]); 561 xmlFreeNode(path->nodesetval->nodeTab[0]); 562 ret = PO_SUCCESS; 563 } else { 564 pool_seterror(POE_BADPARAM); 565 ret = PO_FAIL; 566 } 567 xmlXPathFreeObject(path); 568 xmlXPathFreeContext(ctx); 569 return (ret); 570 } 571 572 /* 573 * Get the data type for an attribute name from the element node. The data 574 * type is returned and the value of the attribute updates the supplied value 575 * pointer. 576 */ 577 static pool_value_class_t 578 pool_xml_get_attr(xmlNodePtr node, xmlChar *name, pool_value_t *value) 579 { 580 pool_value_class_t data_type; 581 xmlChar *data; 582 uint64_t uval; 583 int64_t ival; 584 585 if (xmlHasProp(node, name) == NULL && pool_is_xml_attr(node->doc, 586 (const char *) node->name, (const char *) name) == PO_FALSE) { 587 pool_seterror(POE_BADPARAM); 588 return (POC_INVAL); 589 } 590 if (xmlHasProp(node, BAD_CAST c_a_dtype) == NULL) { 591 pool_seterror(POE_INVALID_CONF); 592 return (POC_INVAL); 593 } 594 data = xmlGetProp(node, name); 595 data_type = get_fast_dtype(node, name); 596 if (data_type != POC_STRING && data == NULL) { 597 pool_seterror(POE_INVALID_CONF); 598 return (POC_INVAL); 599 } 600 switch (data_type) { 601 case POC_UINT: 602 errno = 0; 603 uval = strtoull((char *)data, NULL, 0); 604 if (errno != 0) { 605 data_type = POC_INVAL; 606 } 607 else 608 pool_value_set_uint64(value, uval); 609 break; 610 case POC_INT: 611 errno = 0; 612 ival = strtoll((char *)data, NULL, 0); 613 if (errno != 0) { 614 data_type = POC_INVAL; 615 } 616 else 617 pool_value_set_int64(value, ival); 618 break; 619 case POC_DOUBLE: 620 pool_value_set_double(value, atof((const char *)data)); 621 break; 622 case POC_BOOL: 623 if (strcmp((const char *)data, "true") == 0) 624 pool_value_set_bool(value, PO_TRUE); 625 else 626 pool_value_set_bool(value, PO_FALSE); 627 break; 628 case POC_STRING: 629 if (pool_value_set_string(value, data ? 630 (const char *)data : "") != PO_SUCCESS) { 631 xmlFree(data); 632 return (POC_INVAL); 633 } 634 break; 635 case POC_INVAL: 636 default: 637 break; 638 } 639 xmlFree(data); 640 return (data_type); 641 } 642 643 /* 644 * Set the data type for an attribute name from the element node. The 645 * supplied value is used to update the designated name using the data 646 * type supplied. 647 */ 648 int 649 pool_xml_set_attr(xmlNodePtr node, xmlChar *name, const pool_value_t *value) 650 { 651 xmlChar buf[MAX_PROP_SIZE] = {0}; 652 uint64_t ures; 653 int64_t ires; 654 uchar_t bres; 655 double dres; 656 const char *sres; 657 658 pool_value_class_t data_type; 659 660 if (xmlHasProp(node, name) == NULL && pool_is_xml_attr(node->doc, 661 (const char *) node->name, (const char *) name) == PO_FALSE) { 662 pool_seterror(POE_BADPARAM); 663 return (PO_FAIL); 664 } 665 666 if (xmlHasProp(node, BAD_CAST c_a_dtype) == NULL) { 667 pool_seterror(POE_INVALID_CONF); 668 return (PO_FAIL); 669 } 670 data_type = get_fast_dtype(node, name); 671 if (data_type != value->pv_class) { 672 pool_seterror(POE_BADPARAM); 673 return (PO_FAIL); 674 } 675 switch (value->pv_class) { 676 case POC_UINT: 677 (void) pool_value_get_uint64(value, &ures); 678 (void) snprintf((char *)buf, sizeof (buf), "%llu", 679 (u_longlong_t)ures); 680 break; 681 case POC_INT: 682 (void) pool_value_get_int64(value, &ires); 683 (void) snprintf((char *)buf, sizeof (buf), "%lld", 684 (longlong_t)ires); 685 break; 686 case POC_DOUBLE: 687 (void) pool_value_get_double(value, &dres); 688 (void) snprintf((char *)buf, sizeof (buf), "%f", dres); 689 break; 690 case POC_BOOL: 691 (void) pool_value_get_bool(value, &bres); 692 if (bres == PO_FALSE) 693 (void) snprintf((char *)buf, sizeof (buf), 694 "false"); 695 else 696 (void) snprintf((char *)buf, sizeof (buf), 697 "true"); 698 break; 699 case POC_STRING: 700 (void) pool_value_get_string(value, &sres); 701 if (sres != NULL) 702 (void) snprintf((char *)buf, sizeof (buf), "%s", 703 sres); 704 break; 705 case POC_INVAL: 706 default: 707 break; 708 } 709 if (xmlSetProp(node, name, buf) == NULL) { 710 pool_seterror(POE_DATASTORE); 711 return (PO_FAIL); 712 } 713 return (PO_SUCCESS); 714 } 715 716 /* 717 * Get the data type for a property name from the element node. The data 718 * type is returned and the value of the property updates the supplied value 719 * pointer. The user is responsible for freeing the memory associated with 720 * a string. 721 */ 722 static pool_value_class_t 723 pool_xml_get_prop(xmlNodePtr node, xmlChar *name, pool_value_t *value) 724 { 725 pool_value_class_t data_type; 726 xmlChar *data, *node_data; 727 xmlXPathContextPtr ctx; 728 xmlXPathObjectPtr path; 729 char buf[MAX_PROP_SIZE]; 730 int64_t uval; 731 int64_t ival; 732 733 /* use xpath to find the node with the appropriate value for name */ 734 (void) snprintf(buf, sizeof (buf), "property[@name=\"%s\"]", name); 735 if ((ctx = xmlXPathNewContext(node->doc)) == NULL) { 736 pool_seterror(POE_BADPARAM); 737 return (POC_INVAL); 738 } 739 ctx->node = node; 740 path = xmlXPathEval(BAD_CAST buf, ctx); 741 742 if (path && (path->type == XPATH_NODESET) && 743 (path->nodesetval->nodeNr == 1)) { 744 int i; 745 if (xmlHasProp(path->nodesetval->nodeTab[0], 746 BAD_CAST c_type) == NULL) { 747 xmlXPathFreeObject(path); 748 xmlXPathFreeContext(ctx); 749 pool_seterror(POE_INVALID_CONF); 750 return (POC_INVAL); 751 } 752 /* type is a string representation of the type */ 753 data = xmlGetProp(path->nodesetval->nodeTab[0], 754 BAD_CAST c_type); 755 node_data = xmlNodeGetContent(path->nodesetval->nodeTab[0]); 756 data_type = POC_INVAL; 757 for (i = 0; i < (sizeof (data_type_tags) / 758 sizeof (data_type_tags[0])); i++) { 759 if (strcmp((char *)data, data_type_tags[i]) == 0) { 760 data_type = i; 761 break; 762 } 763 } 764 switch (data_type) { 765 case POC_UINT: 766 errno = 0; 767 uval = strtoull((char *)node_data, NULL, 0); 768 if (errno != 0) 769 data_type = POC_INVAL; 770 else 771 pool_value_set_uint64(value, uval); 772 break; 773 case POC_INT: 774 errno = 0; 775 ival = strtoll((char *)node_data, NULL, 0); 776 if (errno != 0) 777 data_type = POC_INVAL; 778 else 779 pool_value_set_int64(value, ival); 780 break; 781 case POC_DOUBLE: 782 pool_value_set_double(value, 783 atof((const char *)node_data)); 784 break; 785 case POC_BOOL: 786 if (strcmp((const char *)node_data, "true") 787 == 0) 788 pool_value_set_bool(value, PO_TRUE); 789 else 790 pool_value_set_bool(value, PO_FALSE); 791 break; 792 case POC_STRING: 793 if (pool_value_set_string(value, 794 (const char *)node_data) != PO_SUCCESS) { 795 data_type = POC_INVAL; 796 break; 797 } 798 break; 799 case POC_INVAL: 800 default: 801 break; 802 } 803 xmlFree(data); 804 xmlFree(node_data); 805 xmlXPathFreeObject(path); 806 xmlXPathFreeContext(ctx); 807 return (data_type); 808 } else { /* No property exists, clean up and return */ 809 xmlXPathFreeObject(path); 810 xmlXPathFreeContext(ctx); 811 pool_seterror(POE_BADPARAM); 812 return (POC_INVAL); 813 } 814 } 815 816 /* 817 * Set the data type for a property name from the element node. The 818 * supplied value is used to update the designated name using the data 819 * type supplied. 820 */ 821 int 822 pool_xml_set_prop(xmlNodePtr node, xmlChar *name, const pool_value_t *value) 823 { 824 /* First check if we have a property with this name (and type???). */ 825 xmlXPathContextPtr ctx; 826 xmlXPathObjectPtr path; 827 xmlChar buf[MAX_PROP_SIZE]; 828 xmlNodePtr element; 829 uint64_t ures; 830 int64_t ires; 831 uchar_t bres; 832 double dres; 833 const char *sres; 834 835 /* use xpath to find the node with the appropriate value for name */ 836 (void) snprintf((char *)buf, sizeof (buf), "property[@name=\"%s\"]", 837 name); 838 if ((ctx = xmlXPathNewContext(node->doc)) == NULL) { 839 pool_seterror(POE_BADPARAM); 840 return (PO_FAIL); 841 } 842 ctx->node = node; 843 path = xmlXPathEval(buf, ctx); 844 if (path == NULL || path->type != XPATH_NODESET) { 845 xmlXPathFreeObject(path); 846 xmlXPathFreeContext(ctx); 847 pool_seterror(POE_BADPARAM); 848 return (PO_FAIL); 849 } else { 850 if (path->nodesetval->nodeNr == 0) 851 element = property_create 852 (node, (const char *)name, value->pv_class); 853 else if (path->nodesetval->nodeNr == 1) { 854 int i; 855 xmlChar *data; 856 857 element = path->nodesetval->nodeTab[0]; 858 if (xmlHasProp(element, BAD_CAST c_type) == NULL) { 859 xmlXPathFreeObject(path); 860 xmlXPathFreeContext(ctx); 861 pool_seterror(POE_INVALID_CONF); 862 return (PO_FAIL); 863 } 864 data = xmlGetProp(element, BAD_CAST c_type); 865 for (i = 0; i < (sizeof (data_type_tags) / 866 sizeof (data_type_tags[0])); i++) 867 if (strcmp((char *)data, data_type_tags[i]) 868 == 0) { 869 break; 870 } 871 xmlFree(data); 872 if (value->pv_class != i) { 873 xmlXPathFreeObject(path); 874 xmlXPathFreeContext(ctx); 875 pool_seterror(POE_BADPARAM); 876 return (PO_FAIL); 877 } 878 } else { 879 xmlXPathFreeObject(path); 880 xmlXPathFreeContext(ctx); 881 pool_seterror(POE_BADPARAM); 882 return (PO_FAIL); 883 } 884 } 885 886 switch (value->pv_class) { 887 case POC_UINT: 888 (void) pool_value_get_uint64(value, &ures); 889 (void) snprintf((char *)buf, sizeof (buf), "%llu", 890 (u_longlong_t)ures); 891 break; 892 case POC_INT: 893 (void) pool_value_get_int64(value, &ires); 894 (void) snprintf((char *)buf, sizeof (buf), "%lld", 895 (longlong_t)ires); 896 break; 897 case POC_DOUBLE: 898 (void) pool_value_get_double(value, &dres); 899 (void) snprintf((char *)buf, sizeof (buf), "%f", dres); 900 break; 901 case POC_BOOL: 902 (void) pool_value_get_bool(value, &bres); 903 if (bres == PO_FALSE) 904 (void) snprintf((char *)buf, sizeof (buf), 905 "false"); 906 else 907 (void) snprintf((char *)buf, sizeof (buf), 908 "true"); 909 break; 910 case POC_STRING: 911 (void) pool_value_get_string(value, &sres); 912 (void) snprintf((char *)buf, sizeof (buf), "%s", sres); 913 break; 914 case POC_INVAL: 915 default: 916 break; 917 } 918 xmlNodeSetContent(element, buf); 919 xmlXPathFreeObject(path); 920 xmlXPathFreeContext(ctx); 921 return (PO_SUCCESS); 922 } 923 924 /* 925 * Return a NULL terminated array of pool_value_t which represents all 926 * of the properties stored for an element 927 * 928 * Return NULL on failure. It is the caller's responsibility to free 929 * the returned array of values. 930 */ 931 pool_value_t ** 932 pool_xml_get_properties(const pool_elem_t *pe, uint_t *nprops) 933 { 934 pool_value_t **result; 935 pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe; 936 int i, j; 937 pool_conf_t *conf = TO_CONF(pe); 938 xmlElementPtr elemDTD; 939 xmlAttributePtr attr; 940 xmlXPathContextPtr ctx; 941 xmlXPathObjectPtr path; 942 char_buf_t *cb = NULL; 943 944 *nprops = 0; 945 946 elemDTD = xmlGetDtdElementDesc(pxe->pxe_node->doc->extSubset, 947 pxe->pxe_node->name); 948 for (attr = elemDTD->attributes; attr != NULL; attr = attr->nexth) { 949 if (strcmp((const char *)attr->name, c_a_dtype) != 0 || 950 strcmp((const char *)attr->name, c_type) != 0) 951 (*nprops)++; 952 } 953 if ((ctx = xmlXPathNewContext( 954 ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc)) == NULL) { 955 pool_seterror(POE_BADPARAM); 956 return (NULL); 957 } 958 ctx->node = pxe->pxe_node; 959 path = xmlXPathEval(BAD_CAST "property", ctx); 960 961 if (path != NULL && path->type == XPATH_NODESET && 962 path->nodesetval != NULL) 963 (*nprops) += path->nodesetval->nodeNr; 964 965 if ((result = calloc(*nprops + 1, sizeof (pool_value_t *))) == NULL) { 966 xmlXPathFreeObject(path); 967 xmlXPathFreeContext(ctx); 968 pool_seterror(POE_SYSTEM); 969 return (NULL); 970 } 971 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 972 xmlXPathFreeObject(path); 973 xmlXPathFreeContext(ctx); 974 free(result); 975 return (NULL); 976 } 977 /* 978 * Now store our attributes and properties in result 979 */ 980 for (i = 0, attr = elemDTD->attributes; attr != NULL; 981 attr = attr->nexth, i++) { 982 if (strcmp((const char *)attr->name, c_a_dtype) == 0 || 983 strcmp((const char *)attr->name, c_type) == 0) { 984 i--; 985 continue; 986 } 987 result[i] = pool_value_alloc(); 988 if (pool_xml_get_attr(pxe->pxe_node, 989 BAD_CAST attr->name, result[i]) == POC_INVAL) { 990 xmlXPathFreeObject(path); 991 xmlXPathFreeContext(ctx); 992 while (i-- >= 0) 993 pool_value_free(result[i]); 994 free(result); 995 free_char_buf(cb); 996 return (NULL); 997 } 998 if (strcmp((const char *)attr->name, c_type) != 0) { 999 if (set_char_buf(cb, "%s.%s", 1000 pool_elem_class_string(pe), attr->name) != 1001 PO_SUCCESS) { 1002 xmlXPathFreeObject(path); 1003 xmlXPathFreeContext(ctx); 1004 while (i-- >= 0) 1005 pool_value_free(result[i]); 1006 free(result); 1007 free_char_buf(cb); 1008 return (NULL); 1009 } 1010 if (pool_value_set_name(result[i], cb->cb_buf) != 1011 PO_SUCCESS) { 1012 xmlXPathFreeObject(path); 1013 xmlXPathFreeContext(ctx); 1014 while (i-- >= 0) 1015 pool_value_free(result[i]); 1016 free(result); 1017 free_char_buf(cb); 1018 return (NULL); 1019 } 1020 } else { 1021 if (pool_value_set_name(result[i], 1022 (const char *)attr->name) != PO_SUCCESS) { 1023 xmlXPathFreeObject(path); 1024 xmlXPathFreeContext(ctx); 1025 while (i-- >= 0) 1026 pool_value_free(result[i]); 1027 free(result); 1028 free_char_buf(cb); 1029 return (NULL); 1030 } 1031 } 1032 } 1033 free_char_buf(cb); 1034 for (j = 0; j < path->nodesetval->nodeNr; j++, i++) { 1035 xmlChar *name = xmlGetProp(path->nodesetval->nodeTab[j], 1036 BAD_CAST c_name); 1037 1038 result[i] = pool_value_alloc(); 1039 1040 if (pool_xml_get_prop(pxe->pxe_node, name, result[i]) == 1041 POC_INVAL) { 1042 xmlFree(name); 1043 xmlXPathFreeObject(path); 1044 xmlXPathFreeContext(ctx); 1045 while (i-- >= 0) 1046 pool_value_free(result[i]); 1047 free(result); 1048 return (NULL); 1049 } 1050 if (pool_value_set_name(result[i], (const char *)name) != 1051 PO_SUCCESS) { 1052 xmlFree(name); 1053 xmlXPathFreeObject(path); 1054 xmlXPathFreeContext(ctx); 1055 while (i-- >= 0) 1056 pool_value_free(result[i]); 1057 free(result); 1058 return (NULL); 1059 } 1060 xmlFree(name); 1061 } 1062 xmlXPathFreeObject(path); 1063 xmlXPathFreeContext(ctx); 1064 return (result); 1065 } 1066 1067 /* 1068 * Store a pointer to one of our data types in the _private member of each 1069 * XML data node contained within the passed node. Note this function is 1070 * recursive and so all sub-nodes are also shadowed. Only shadow the nodes 1071 * which we are interested in, i.e. system, pool, res and comp 1072 */ 1073 static int 1074 create_shadow(xmlNodePtr node) 1075 { 1076 xmlNodePtr sib; 1077 int ret = PO_SUCCESS; 1078 /* Create a data structure of the appropriate type */ 1079 1080 if (0 == (xmlStrcmp(node->name, 1081 BAD_CAST element_class_tags[PEC_SYSTEM]))) { 1082 ret = pool_xml_elem_wrap(node, PEC_SYSTEM, PREC_INVALID, 1083 PCEC_INVALID); 1084 } else if (0 == (xmlStrcmp(node->name, 1085 BAD_CAST element_class_tags[PEC_POOL]))) { 1086 ret = pool_xml_elem_wrap(node, PEC_POOL, PREC_INVALID, 1087 PCEC_INVALID); 1088 } else if (0 == (xmlStrcmp(node->name, 1089 BAD_CAST element_class_tags[PEC_RES_COMP]))) { 1090 xmlChar *data; 1091 pool_resource_elem_class_t res_class; 1092 data = xmlGetProp(node, BAD_CAST c_type); 1093 1094 res_class = pool_resource_elem_class_from_string((char *)data); 1095 xmlFree(data); 1096 ret = pool_xml_elem_wrap(node, PEC_RES_COMP, res_class, 1097 PCEC_INVALID); 1098 } else if (0 == (xmlStrcmp(node->name, 1099 BAD_CAST element_class_tags[PEC_RES_AGG]))) { 1100 xmlChar *data; 1101 pool_resource_elem_class_t res_class; 1102 data = xmlGetProp(node, BAD_CAST c_type); 1103 1104 res_class = pool_resource_elem_class_from_string((char *)data); 1105 xmlFree(data); 1106 ret = pool_xml_elem_wrap(node, PEC_RES_AGG, res_class, 1107 PCEC_INVALID); 1108 } else if (0 == (xmlStrcmp(node->name, 1109 BAD_CAST element_class_tags[PEC_COMP]))) { 1110 xmlChar *data; 1111 pool_component_elem_class_t comp_class; 1112 data = xmlGetProp(node, BAD_CAST c_type); 1113 1114 comp_class = pool_component_elem_class_from_string( 1115 (char *)data); 1116 xmlFree(data); 1117 ret = pool_xml_elem_wrap(node, PEC_COMP, PREC_INVALID, 1118 comp_class); 1119 } 1120 /* Have to shadow all children and all siblings */ 1121 for (sib = node->children; sib != NULL; sib = sib->next) { 1122 if ((ret = create_shadow(sib)) != PO_SUCCESS) 1123 break; 1124 } 1125 return (ret); 1126 } 1127 1128 1129 /* 1130 * XML Data access and navigation APIs 1131 */ 1132 1133 /* 1134 * Close the configuration. There are a few steps to closing a configuration: 1135 * - Unlock the backing file (if there is one) 1136 * - Close the file (if there is one) 1137 * - Free the shadow memory }Done in pool_xml_free_doc 1138 * - Free the document } 1139 * - Free the data provider for this configuration 1140 * - Free the configuration location specifier 1141 * Returns PO_SUCCESS/PO_FAIL 1142 */ 1143 static int 1144 pool_xml_close(pool_conf_t *conf) 1145 { 1146 pool_xml_connection_t *pxc = (pool_xml_connection_t *)conf->pc_prov; 1147 int ret = PO_SUCCESS; 1148 1149 if (pxc->pxc_file != NULL) { 1150 /* Close (and implicitly) unlock the file */ 1151 if (fclose(pxc->pxc_file) != 0) { 1152 pool_seterror(POE_SYSTEM); 1153 ret = PO_FAIL; 1154 } 1155 pxc->pxc_file = NULL; 1156 } 1157 /* Close the xml specific parts */ 1158 (void) pool_xml_free_doc(conf); 1159 pool_xml_connection_free((pool_xml_connection_t *)conf->pc_prov); 1160 return (ret); 1161 } 1162 1163 /* 1164 * Remove the configuration from the backing store. In XML terms delete 1165 * the file backing the configuration. You need a copy of the location 1166 * since the pool_conf_close function, frees the location. 1167 * Returns PO_SUCCESS/PO_FAIL 1168 */ 1169 static int 1170 pool_xml_remove(pool_conf_t *conf) 1171 { 1172 if (pool_conf_location(conf) != NULL) { 1173 /* First unlink the file, to prevent races on open */ 1174 if (unlink(pool_conf_location(conf)) != 0) { 1175 pool_seterror(POE_SYSTEM); 1176 return (PO_FAIL); 1177 } 1178 /* Now close the configuration */ 1179 (void) pool_conf_close(conf); 1180 return (PO_SUCCESS); 1181 } 1182 return (PO_FAIL); 1183 } 1184 1185 /* 1186 * Validate the configuration. There are three levels of validation, loose, 1187 * strict and runtime. In this, XML, implementation, loose is mapped to XML 1188 * validation, strict implements additional application level validation 1189 * checks, e.g. all pools must have unique names, runtime ensures that this 1190 * configuration would instantiate on the current system. 1191 * 1192 * Returns PO_SUCCESS/PO_FAIL 1193 */ 1194 static int 1195 pool_xml_validate(const pool_conf_t *conf, pool_valid_level_t level) 1196 { 1197 pool_xml_connection_t *pxc = (pool_xml_connection_t *)conf->pc_prov; 1198 xmlValidCtxtPtr cvp; 1199 1200 if ((cvp = xmlNewValidCtxt()) == NULL) { 1201 pool_seterror(POE_INVALID_CONF); 1202 return (PO_FAIL); 1203 } 1204 cvp->error = pool_error_func; 1205 cvp->warning = pool_error_func; 1206 1207 if (xmlValidateDocument(cvp, pxc->pxc_doc) == 0) { 1208 xmlFreeValidCtxt(cvp); 1209 pool_seterror(POE_INVALID_CONF); 1210 return (PO_FAIL); 1211 } 1212 xmlFreeValidCtxt(cvp); 1213 1214 if (level >= POV_RUNTIME) { 1215 /* 1216 * Note: This is resource specific. 1217 */ 1218 return (((pool_validate_resource(conf, "pset", c_min_prop, 0) == 1219 PO_SUCCESS) && 1220 (pool_validate_resource(conf, "pset", c_max_prop, 0) == 1221 PO_SUCCESS)) ? PO_SUCCESS : PO_FAIL); 1222 } 1223 return (PO_SUCCESS); 1224 } 1225 1226 /* 1227 * Commit the configuration to the backing store. In XML terms this means 1228 * write the changes to the backing file. Read the comments below for details 1229 * on exactly how this operation is performed. 1230 * Returns PO_SUCCESS/PO_FAIL 1231 */ 1232 static int 1233 pool_xml_commit(pool_conf_t *conf) 1234 { 1235 pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; 1236 xmlOutputBufferPtr buf; 1237 1238 /* 1239 * Ensure that the configuration file has no contents 1240 */ 1241 if (fseek(prov->pxc_file, 0, SEEK_SET) != 0) { 1242 pool_seterror(POE_SYSTEM); 1243 return (PO_FAIL); 1244 } 1245 1246 if (ftruncate(fileno(prov->pxc_file), 0) == -1) { 1247 pool_seterror(POE_SYSTEM); 1248 return (PO_FAIL); 1249 } 1250 /* 1251 * Create an XML output buffer and write out the contents of the 1252 * configuration to the file. 1253 */ 1254 if ((buf = xmlOutputBufferCreateFile(prov->pxc_file, NULL)) == NULL) { 1255 pool_seterror(POE_DATASTORE); 1256 return (PO_FAIL); 1257 } 1258 1259 if (xmlSaveFormatFileTo(buf, prov->pxc_doc, NULL, 1) == -1) { 1260 pool_seterror(POE_DATASTORE); 1261 return (PO_FAIL); 1262 } 1263 1264 return (PO_SUCCESS); 1265 } 1266 1267 /* 1268 * Export the configuration in the specified format to the specified location. 1269 * The only format implemented now is the native format, which saves the 1270 * active configuration to the supplied location. 1271 * Returns PO_SUCCESS/PO_FAIL 1272 */ 1273 static int 1274 pool_xml_export(const pool_conf_t *conf, const char *location, 1275 pool_export_format_t fmt) 1276 { 1277 int ret; 1278 1279 switch (fmt) { 1280 case POX_NATIVE: 1281 ret = xmlSaveFormatFile(location, 1282 ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc, 1283 1); 1284 if (ret == -1) { 1285 pool_seterror(POE_SYSTEM); 1286 return (PO_FAIL); 1287 } else 1288 return (PO_SUCCESS); 1289 1290 default: 1291 pool_seterror(POE_BADPARAM); 1292 return (PO_FAIL); 1293 } 1294 } 1295 1296 /* 1297 * Discard the configuration and restore the configuration to the values 1298 * specified in the configuration location. 1299 * Returns PO_SUCCESS/PO_FAIL 1300 */ 1301 static int 1302 pool_xml_rollback(pool_conf_t *conf) 1303 { 1304 pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; 1305 1306 /* Rollback the file pointer ready for the reparse */ 1307 if (fseek(prov->pxc_file, 0, SEEK_SET) != 0) { 1308 pool_seterror(POE_SYSTEM); 1309 return (PO_FAIL); 1310 } 1311 /* Reparse the document */ 1312 /* In XML terms this means, discard and reparse the document */ 1313 (void) pool_xml_free_doc(conf); 1314 if (pool_xml_parse_document(conf) == PO_FAIL) 1315 return (PO_FAIL); 1316 return (PO_SUCCESS); 1317 } 1318 1319 /* 1320 * Allocate a new pool_elem_t in the supplied configuration of the specified 1321 * class. 1322 * Returns element pointer/NULL 1323 */ 1324 static void 1325 pool_xml_elem_init(pool_conf_t *conf, pool_xml_elem_t *elem, 1326 pool_elem_class_t class, pool_resource_elem_class_t res_class, 1327 pool_component_elem_class_t comp_class) 1328 { 1329 pool_elem_t *pe = TO_ELEM(elem); 1330 pe->pe_conf = conf; 1331 pe->pe_class = class; 1332 pe->pe_resource_class = res_class; 1333 pe->pe_component_class = comp_class; 1334 /* Set up the function pointers for element manipulation */ 1335 pe->pe_get_prop = pool_xml_get_property; 1336 pe->pe_put_prop = pool_xml_put_property; 1337 pe->pe_rm_prop = pool_xml_rm_property; 1338 pe->pe_get_props = pool_xml_get_properties; 1339 pe->pe_remove = pool_xml_elem_remove; 1340 pe->pe_get_container = pool_xml_get_container; 1341 pe->pe_set_container = pool_xml_set_container; 1342 /* 1343 * Specific initialisation for different types of element 1344 */ 1345 if (class == PEC_POOL) { 1346 pool_xml_pool_t *pp = (pool_xml_pool_t *)elem; 1347 pp->pp_associate = pool_xml_pool_associate; 1348 pp->pp_dissociate = pool_xml_pool_dissociate; 1349 } 1350 if (class == PEC_RES_COMP || class == PEC_RES_AGG) { 1351 pool_xml_resource_t *pr = (pool_xml_resource_t *)elem; 1352 pr->pr_is_system = pool_xml_resource_is_system; 1353 pr->pr_can_associate = pool_xml_resource_can_associate; 1354 } 1355 } 1356 1357 /* 1358 * "Wrap" a suplied XML node with a pool_elem_t sub-type of the supplied 1359 * class. 1360 * Returns PO_SUCCESS/PO_FAIL 1361 */ 1362 static int 1363 pool_xml_elem_wrap(xmlNodePtr node, pool_elem_class_t class, 1364 pool_resource_elem_class_t res_class, 1365 pool_component_elem_class_t comp_class) 1366 { 1367 pool_conf_t *conf = node->doc->_private; 1368 pool_xml_elem_t *elem; 1369 /* Need to do some messing about to support SubTypes */ 1370 switch (class) { 1371 case PEC_SYSTEM: 1372 if ((elem = malloc(sizeof (pool_xml_system_t))) == NULL) { 1373 pool_seterror(POE_SYSTEM); 1374 return (PO_FAIL); 1375 } 1376 (void) memset(elem, 0, sizeof (pool_xml_system_t)); 1377 break; 1378 case PEC_POOL: 1379 if ((elem = malloc(sizeof (pool_xml_pool_t))) == NULL) { 1380 pool_seterror(POE_SYSTEM); 1381 return (PO_FAIL); 1382 } 1383 (void) memset(elem, 0, sizeof (pool_xml_pool_t)); 1384 break; 1385 case PEC_RES_COMP: 1386 case PEC_RES_AGG: 1387 if ((elem = malloc(sizeof (pool_xml_resource_t))) == NULL) { 1388 pool_seterror(POE_SYSTEM); 1389 return (PO_FAIL); 1390 } 1391 (void) memset(elem, 0, sizeof (pool_xml_resource_t)); 1392 break; 1393 case PEC_COMP: 1394 if ((elem = malloc(sizeof (pool_xml_component_t))) == NULL) { 1395 pool_seterror(POE_SYSTEM); 1396 return (PO_FAIL); 1397 } 1398 (void) memset(elem, 0, sizeof (pool_xml_component_t)); 1399 break; 1400 } 1401 pool_xml_elem_init(conf, elem, class, res_class, comp_class); 1402 node->_private = elem; 1403 elem->pxe_node = node; 1404 return (PO_SUCCESS); 1405 } 1406 1407 /* 1408 * Associate a pool to the default resource for the supplied resource 1409 * type. 1410 */ 1411 int 1412 pool_assoc_default_resource_type(pool_t *pool, pool_resource_elem_class_t type) 1413 { 1414 pool_value_t *props[] = { NULL, NULL, NULL }; 1415 uint_t rl_size; 1416 pool_resource_t **rsl; 1417 pool_conf_t *conf = TO_ELEM(pool)->pe_conf; 1418 char_buf_t *cb = NULL; 1419 pool_value_t val0 = POOL_VALUE_INITIALIZER; 1420 pool_value_t val1 = POOL_VALUE_INITIALIZER; 1421 1422 props[0] = &val0; 1423 props[1] = &val1; 1424 1425 1426 if (pool_value_set_string(props[0], pool_resource_type_string(type)) != 1427 PO_SUCCESS || 1428 pool_value_set_name(props[0], c_type) != PO_SUCCESS) { 1429 return (PO_FAIL); 1430 } 1431 1432 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) { 1433 return (PO_FAIL); 1434 } 1435 1436 if (set_char_buf(cb, "%s.default", 1437 pool_resource_type_string(type)) != 1438 PO_SUCCESS) { 1439 free_char_buf(cb); 1440 return (PO_FAIL); 1441 } 1442 if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) { 1443 free_char_buf(cb); 1444 return (PO_FAIL); 1445 } 1446 pool_value_set_bool(props[1], PO_TRUE); 1447 free_char_buf(cb); 1448 1449 if ((rsl = pool_query_resources(conf, &rl_size, props)) == NULL) { 1450 pool_seterror(POE_INVALID_CONF); 1451 return (PO_FAIL); 1452 } 1453 1454 /* 1455 * One default resource set per type 1456 */ 1457 if (rl_size != 1) { 1458 free(rsl); 1459 pool_seterror(POE_INVALID_CONF); 1460 return (PO_FAIL); 1461 } 1462 if (pool_associate(conf, pool, rsl[0]) < 0) { 1463 free(rsl); 1464 pool_seterror(POE_INVALID_CONF); 1465 return (PO_FAIL); 1466 } 1467 free(rsl); 1468 return (PO_SUCCESS); 1469 } 1470 1471 /* 1472 * Create an XML node in the supplied configuration with a pool_elem_t 1473 * sub-type of the supplied class. 1474 * Returns pool_elem_t pointer/NULL 1475 */ 1476 static pool_elem_t * 1477 pool_xml_elem_create(pool_conf_t *conf, pool_elem_class_t class, 1478 pool_resource_elem_class_t res_class, 1479 pool_component_elem_class_t comp_class) 1480 { 1481 /* In XML terms, create an element of the appropriate class */ 1482 pool_xml_elem_t *elem; 1483 pool_elem_t *parent; 1484 pool_system_t *parent_system; 1485 1486 if (class == PEC_INVALID) { 1487 pool_seterror(POE_BADPARAM); 1488 return (NULL); 1489 } 1490 1491 /* Now create the XML component and add to it's parent */ 1492 /* 1493 * If we know the class of an element, we know it's parent. 1494 * PEC_POOL, the parent must be the system node 1495 * PEC_RES, treat as pool. 1496 * PEC_COMP, we don't know the parent, leave this up to the 1497 * create_comp function. 1498 */ 1499 /* Since we know the subtype we can create and populate the sub-type */ 1500 switch (class) { 1501 case PEC_POOL: 1502 if ((parent_system = pool_conf_system(conf)) == NULL) { 1503 pool_seterror(POE_INVALID_CONF); 1504 return (NULL); 1505 } 1506 if ((parent = pool_system_elem(parent_system)) == NULL) { 1507 pool_seterror(POE_INVALID_CONF); 1508 return (NULL); 1509 } 1510 if ((elem = malloc(sizeof (pool_xml_system_t))) == NULL) { 1511 pool_seterror(POE_SYSTEM); 1512 return (NULL); 1513 } 1514 (void) memset(elem, 0, sizeof (pool_xml_system_t)); 1515 if ((elem->pxe_node = node_create_with_id( 1516 ((pool_xml_elem_t *)parent)->pxe_node, 1517 BAD_CAST element_class_tags[class])) == NULL) { 1518 pool_seterror(POE_DATASTORE); 1519 (void) pool_xml_elem_remove((pool_elem_t *)elem); 1520 return (NULL); 1521 } 1522 break; 1523 case PEC_RES_COMP: 1524 case PEC_RES_AGG: 1525 if ((parent_system = pool_conf_system(conf)) == NULL) { 1526 pool_seterror(POE_INVALID_CONF); 1527 return (NULL); 1528 } 1529 if ((parent = pool_system_elem(parent_system)) == NULL) { 1530 pool_seterror(POE_INVALID_CONF); 1531 return (NULL); 1532 } 1533 if ((elem = malloc(sizeof (pool_xml_resource_t))) == NULL) { 1534 pool_seterror(POE_SYSTEM); 1535 return (NULL); 1536 } 1537 (void) memset(elem, 0, sizeof (pool_xml_resource_t)); 1538 if ((elem->pxe_node = node_create_with_id 1539 (((pool_xml_elem_t *)parent)->pxe_node, 1540 BAD_CAST element_class_tags[class])) == NULL) { 1541 pool_seterror(POE_DATASTORE); 1542 (void) pool_xml_elem_remove((pool_elem_t *)elem); 1543 return (NULL); 1544 } 1545 break; 1546 case PEC_COMP: 1547 if ((elem = malloc(sizeof (pool_xml_component_t))) == NULL) { 1548 pool_seterror(POE_SYSTEM); 1549 return (NULL); 1550 } 1551 (void) memset(elem, 0, sizeof (pool_xml_component_t)); 1552 if ((elem->pxe_node = node_create(NULL, 1553 BAD_CAST element_class_tags[class])) == NULL) { 1554 pool_seterror(POE_DATASTORE); 1555 (void) pool_xml_elem_remove((pool_elem_t *)elem); 1556 return (NULL); 1557 } 1558 break; 1559 default: 1560 pool_seterror(POE_BADPARAM); 1561 return (NULL); 1562 } 1563 pool_xml_elem_init(conf, elem, class, res_class, comp_class); 1564 elem->pxe_node->_private = elem; 1565 if (class == PEC_RES_COMP || class == PEC_RES_AGG || 1566 class == PEC_COMP) { 1567 /* 1568 * Put the type and an invalid sys_id on the node. 1569 */ 1570 if (xmlSetProp(elem->pxe_node, BAD_CAST c_sys_prop, 1571 BAD_CAST POOL_SYSID_BAD_STRING) == NULL) { 1572 pool_seterror(POE_DATASTORE); 1573 (void) pool_xml_elem_remove((pool_elem_t *)elem); 1574 return (NULL); 1575 } 1576 if (xmlSetProp(elem->pxe_node, BAD_CAST c_type, 1577 BAD_CAST pool_elem_class_string( 1578 (pool_elem_t *)elem)) == NULL) { 1579 pool_seterror(POE_DATASTORE); 1580 (void) pool_xml_elem_remove((pool_elem_t *)elem); 1581 return (NULL); 1582 } 1583 } 1584 if (class == PEC_POOL) { 1585 /* 1586 * Note: This is resource specific. 1587 */ 1588 if (pool_assoc_default_resource_type(pool_elem_pool( 1589 (pool_elem_t *)elem), PREC_PSET) == PO_FAIL) { 1590 (void) pool_xml_elem_remove((pool_elem_t *)elem); 1591 return (NULL); 1592 } 1593 } 1594 return ((pool_elem_t *)elem); 1595 } 1596 1597 /* 1598 * Allocate a data provider for the supplied configuration and optionally 1599 * discover resources. 1600 * The data provider is the cross over point from the "abstract" configuration 1601 * functions into the data representation specific manipulation routines. 1602 * This function sets up all the required pointers to create an XML aware 1603 * data provider. 1604 * Returns PO_SUCCESS/PO_FAIL 1605 */ 1606 int 1607 pool_xml_connection_alloc(pool_conf_t *conf, int oflags) 1608 { 1609 pool_xml_connection_t *prov; 1610 1611 xml_init(); 1612 if ((prov = malloc(sizeof (pool_xml_connection_t))) == NULL) { 1613 pool_seterror(POE_SYSTEM); 1614 return (PO_FAIL); 1615 } 1616 (void) memset(prov, 0, sizeof (pool_xml_connection_t)); 1617 /* 1618 * Initialise data members 1619 */ 1620 prov->pc_name = strdup("LIBXML 2.4.0"); 1621 prov->pc_store_type = XML_DATA_STORE; 1622 prov->pc_oflags = oflags; 1623 /* 1624 * Initialise function pointers 1625 */ 1626 prov->pc_close = pool_xml_close; 1627 prov->pc_validate = pool_xml_validate; 1628 prov->pc_commit = pool_xml_commit; 1629 prov->pc_export = pool_xml_export; 1630 prov->pc_rollback = pool_xml_rollback; 1631 prov->pc_exec_query = pool_xml_exec_query; 1632 prov->pc_elem_create = pool_xml_elem_create; 1633 prov->pc_remove = pool_xml_remove; 1634 prov->pc_res_xfer = pool_xml_res_transfer; 1635 prov->pc_res_xxfer = pool_xml_res_xtransfer; 1636 /* 1637 * End of common initialisation 1638 */ 1639 /* 1640 * Associate the provider to it's configuration 1641 */ 1642 conf->pc_prov = (pool_connection_t *)prov; 1643 /* 1644 * At this point the configuration provider has been initialized, 1645 * mark the configuration as valid so that the various routines 1646 * which rely on a valid configuration will work correctly. 1647 */ 1648 conf->pc_state = POF_VALID; 1649 1650 if ((oflags & PO_CREAT) != 0) { 1651 pool_conf_t *dyn; 1652 1653 if ((dyn = pool_conf_alloc()) == NULL) 1654 return (PO_FAIL); 1655 1656 if (pool_conf_open(dyn, pool_dynamic_location(), 1657 PO_RDONLY) != PO_SUCCESS) { 1658 pool_conf_free(dyn); 1659 return (PO_FAIL); 1660 } 1661 1662 if (pool_conf_export(dyn, conf->pc_location, 1663 POX_NATIVE) != PO_SUCCESS) { 1664 (void) pool_conf_close(dyn); 1665 pool_conf_free(dyn); 1666 return (PO_FAIL); 1667 } 1668 (void) pool_conf_close(dyn); 1669 pool_conf_free(dyn); 1670 } 1671 1672 if (pool_xml_open_file(conf) == PO_FAIL) { 1673 (void) pool_xml_close(conf); 1674 return (PO_FAIL); 1675 } 1676 1677 return (PO_SUCCESS); 1678 } 1679 1680 /* 1681 * Free the resources for an XML data provider. 1682 */ 1683 static void 1684 pool_xml_connection_free(pool_xml_connection_t *prov) 1685 { 1686 free((void *)prov->pc_name); 1687 free(prov); 1688 } 1689 1690 /* 1691 * Allocate a result set. The Result Set stores the result of an XPath 1692 * query along with the parameters used to create the result set (for 1693 * debugging purposes). 1694 * Returns pool_xml_result_set_t pointer/NULL 1695 */ 1696 static pool_xml_result_set_t * 1697 pool_xml_result_set_alloc(const pool_conf_t *conf) 1698 { 1699 pool_xml_result_set_t *rs; 1700 1701 if ((rs = malloc(sizeof (pool_xml_result_set_t))) == NULL) { 1702 pool_seterror(POE_SYSTEM); 1703 return (NULL); 1704 } 1705 (void) memset(rs, 0, sizeof (pool_xml_result_set_t)); 1706 rs->prs_conf = conf; 1707 rs->prs_index = -1; 1708 rs->prs_active = PO_TRUE; 1709 /* Fix up the result set accessor functions to the xml specfic ones */ 1710 rs->prs_next = pool_xml_rs_next; 1711 rs->prs_prev = pool_xml_rs_prev; 1712 rs->prs_first = pool_xml_rs_first; 1713 rs->prs_last = pool_xml_rs_last; 1714 rs->prs_get_index = pool_xml_rs_get_index; 1715 rs->prs_set_index = pool_xml_rs_set_index; 1716 rs->prs_close = pool_xml_rs_close; 1717 rs->prs_count = pool_xml_rs_count; 1718 return (rs); 1719 } 1720 1721 /* 1722 * Free a result set. Ensure that the resources are all released at this point. 1723 */ 1724 static void 1725 pool_xml_result_set_free(pool_xml_result_set_t *rs) 1726 { 1727 if (rs->pxr_path != NULL) 1728 xmlXPathFreeObject(rs->pxr_path); 1729 if (rs->pxr_ctx != NULL) 1730 xmlXPathFreeContext(rs->pxr_ctx); 1731 free(rs); 1732 } 1733 1734 /* 1735 * Transfer size from one resource to another. 1736 * Returns PO_SUCCESS/PO_FAIL 1737 */ 1738 /* ARGSUSED */ 1739 int 1740 pool_xml_res_transfer(pool_resource_t *src, pool_resource_t *tgt, uint64_t size) 1741 { 1742 return (PO_SUCCESS); 1743 } 1744 1745 /* 1746 * Transfer components rl from one resource to another. 1747 * Returns PO_SUCCESS/PO_FAIL 1748 */ 1749 /* ARGSUSED */ 1750 int 1751 pool_xml_res_xtransfer(pool_resource_t *src, pool_resource_t *tgt, 1752 pool_component_t **rl) { 1753 int i; 1754 1755 /* 1756 * Walk the Result Set and move the resource components 1757 */ 1758 for (i = 0; rl[i] != NULL; i++) { 1759 if (pool_set_container(TO_ELEM(tgt), TO_ELEM(rl[i])) == 1760 PO_FAIL) { 1761 return (PO_FAIL); 1762 } 1763 } 1764 return (PO_SUCCESS); 1765 } 1766 1767 /* 1768 * Return the next element in a result set. 1769 * Returns pool_elem_t pointer/NULL 1770 */ 1771 static pool_elem_t * 1772 pool_xml_rs_next(pool_result_set_t *set) 1773 { 1774 pool_elem_t *next; 1775 /* Since I know this is an XML result set */ 1776 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1777 1778 /* Update the context node */ 1779 if (xset->prs_index == xset->pxr_path->nodesetval->nodeNr - 1) 1780 return (NULL); 1781 next = 1782 xset->pxr_path->nodesetval->nodeTab[++xset->prs_index]->_private; 1783 return (next); 1784 } 1785 1786 /* 1787 * Return the previous element in a result set. 1788 * Returns pool_elem_t pointer/NULL 1789 */ 1790 static pool_elem_t * 1791 pool_xml_rs_prev(pool_result_set_t *set) 1792 { 1793 pool_elem_t *prev; 1794 /* Since I know this is an XML result set */ 1795 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1796 1797 /* Update the context node */ 1798 if (xset->prs_index < 0) 1799 return (NULL); 1800 prev = 1801 xset->pxr_path->nodesetval->nodeTab[xset->prs_index--]->_private; 1802 return (prev); 1803 } 1804 1805 /* 1806 * Sets the current index in a result set. 1807 * Returns PO_SUCCESS/PO_FAIL 1808 */ 1809 static int 1810 pool_xml_rs_set_index(pool_result_set_t *set, int index) 1811 { 1812 /* Since I know this is an XML result set */ 1813 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1814 1815 if (index < 0 || index >= xset->pxr_path->nodesetval->nodeNr) { 1816 pool_seterror(POE_BADPARAM); 1817 return (PO_FAIL); 1818 } 1819 xset->prs_index = index; 1820 return (PO_SUCCESS); 1821 } 1822 1823 /* 1824 * Return the current index in a result set. 1825 * Returns current index 1826 */ 1827 static int 1828 pool_xml_rs_get_index(pool_result_set_t *set) 1829 { 1830 /* Since I know this is an XML result set */ 1831 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1832 1833 return (xset->prs_index); 1834 } 1835 1836 /* 1837 * Return the first element in a result set. 1838 * Returns pool_elem_t pointer/NULL 1839 */ 1840 static pool_elem_t * 1841 pool_xml_rs_first(pool_result_set_t *set) 1842 { 1843 /* Since I know this is an XML result set */ 1844 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1845 1846 /* Update the context node */ 1847 return (xset->pxr_path->nodesetval->nodeTab[0]->_private); 1848 } 1849 1850 /* 1851 * Return the last element in a result set. 1852 * Returns pool_elem_t pointer/NULL 1853 */ 1854 static pool_elem_t * 1855 pool_xml_rs_last(pool_result_set_t *set) 1856 { 1857 /* Since I know this is an XML result set */ 1858 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1859 1860 /* Update the context node */ 1861 return (xset->pxr_path->nodesetval-> 1862 nodeTab[xset->pxr_path->nodesetval->nodeNr-1]->_private); 1863 } 1864 1865 /* 1866 * Return the number of results in a result set. 1867 * Returns result count 1868 */ 1869 static int 1870 pool_xml_rs_count(pool_result_set_t *set) 1871 { 1872 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1873 1874 return (xset->pxr_path->nodesetval->nodeNr); 1875 } 1876 1877 1878 /* 1879 * Close a result set. Remove this result set from the list of results and 1880 * free the resources 1881 * Returns PO_SUCCESS/PO_FAIL 1882 */ 1883 static int 1884 pool_xml_rs_close(pool_result_set_t *set) 1885 { 1886 pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set; 1887 1888 pool_xml_result_set_free(xset); 1889 return (PO_SUCCESS); 1890 } 1891 1892 /* 1893 * Set the container for a node. 1894 * Returns PO_SUCCESS/PO_FAIL 1895 */ 1896 static int 1897 pool_xml_set_container(pool_elem_t *pp, pool_elem_t *pc) 1898 { 1899 pool_xml_elem_t *pxp; 1900 pool_xml_elem_t *pxc; 1901 xmlNodePtr parent; 1902 1903 pxp = (pool_xml_elem_t *)pp; 1904 pxc = (pool_xml_elem_t *)pc; 1905 parent = pxc->pxe_node->parent; 1906 1907 xmlUnlinkNode(pxc->pxe_node); 1908 if (xmlAddChild(pxp->pxe_node, pxc->pxe_node) == NULL) { 1909 /* Try to move back */ 1910 (void) xmlAddChild(parent, pxc->pxe_node); 1911 pool_seterror(POE_INVALID_CONF); 1912 return (PO_FAIL); 1913 } 1914 pc->pe_conf = pp->pe_conf; 1915 return (PO_SUCCESS); 1916 } 1917 /* 1918 * Get the container for a node. 1919 * Returns Container/NULL 1920 */ 1921 static pool_elem_t * 1922 pool_xml_get_container(const pool_elem_t *pc) 1923 { 1924 pool_xml_elem_t *pxc = (pool_xml_elem_t *)pc; 1925 1926 return ((pool_elem_t *)pxc->pxe_node->parent->_private); 1927 } 1928 1929 /* 1930 * Note: This function is resource specific, needs extending for other 1931 * resource types. 1932 */ 1933 int 1934 pool_xml_resource_is_system(const pool_resource_t *pr) 1935 { 1936 switch (pool_resource_elem_class(TO_ELEM(pr))) { 1937 case PREC_PSET: 1938 return (PSID_IS_SYSSET( 1939 elem_get_sysid(TO_ELEM(pr)))); 1940 default: 1941 return (PO_FALSE); 1942 } 1943 } 1944 1945 /* 1946 * Note: This function is resource specific, needs extending for other 1947 * resource types. 1948 */ 1949 int 1950 pool_xml_resource_can_associate(const pool_resource_t *pr) 1951 { 1952 switch (pool_resource_elem_class(TO_ELEM(pr))) { 1953 case PREC_PSET: 1954 return (PO_TRUE); 1955 default: 1956 return (PO_FALSE); 1957 } 1958 } 1959 1960 /* 1961 * Note: This function is resource specific. It must be extended to support 1962 * multiple resource types. 1963 */ 1964 int 1965 pool_xml_pool_associate(pool_t *pool, const pool_resource_t *pr) 1966 { 1967 pool_value_t val = POOL_VALUE_INITIALIZER; 1968 1969 if (pool_xml_get_property(TO_ELEM(pr), 1970 "pset.ref_id", &val) != POC_STRING) 1971 return (PO_FAIL); 1972 if (pool_xml_put_property(TO_ELEM(pool), "pool.res", &val) != 1973 PO_SUCCESS) 1974 return (PO_FAIL); 1975 return (PO_SUCCESS); 1976 } 1977 1978 /* 1979 * pool_xml_pool_dissociate() simply finds the default resource for 1980 * the type of resource being dissociated and then calls 1981 * pool_xml_pool_associate() to associate to the default resource. 1982 */ 1983 int 1984 pool_xml_pool_dissociate(pool_t *pool, const pool_resource_t *pr) 1985 { 1986 const pool_resource_t *default_res; 1987 1988 if ((default_res = get_default_resource(pr)) == NULL) 1989 return (PO_FAIL); 1990 if (default_res == pr) 1991 return (PO_SUCCESS); 1992 return (pool_xml_pool_associate(pool, default_res)); 1993 } 1994 1995 /* 1996 * pool_xml_open_file() opens a file for a configuration. This establishes 1997 * the locks required to ensure data integrity when manipulating a 1998 * configuration. 1999 * Returns PO_SUCCESS/PO_FAIL 2000 */ 2001 static int 2002 pool_xml_open_file(pool_conf_t *conf) 2003 { 2004 struct flock lock; 2005 struct stat s; 2006 2007 pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; 2008 2009 /* 2010 * Always close the pxc_file in case there was a previously failed open 2011 */ 2012 if (prov->pxc_file != NULL) { 2013 (void) fclose(prov->pxc_file); 2014 prov->pxc_file = NULL; 2015 } 2016 2017 /* 2018 * Check that the DTD required for this operation is present. 2019 * If it isn't fail 2020 */ 2021 if (dtd_exists(dtd_location) == PO_FALSE) { 2022 pool_seterror(POE_DATASTORE); 2023 return (PO_FAIL); 2024 } 2025 2026 if ((prov->pc_oflags & PO_RDWR) != 0) 2027 prov->pxc_file = fopen(conf->pc_location, "r+F"); 2028 else /* Assume opening PO_RDONLY */ 2029 prov->pxc_file = fopen(conf->pc_location, "rF"); 2030 2031 if (prov->pxc_file == NULL) { 2032 pool_seterror(POE_SYSTEM); 2033 return (PO_FAIL); 2034 } 2035 2036 /* 2037 * Setup the lock for the file 2038 */ 2039 lock.l_type = (prov->pc_oflags & PO_RDWR) ? F_WRLCK : F_RDLCK; 2040 lock.l_whence = SEEK_SET; 2041 lock.l_start = 0; 2042 lock.l_len = 0; 2043 if (fcntl(fileno(prov->pxc_file), F_SETLKW, &lock) == -1) { 2044 pool_seterror(POE_SYSTEM); 2045 return (PO_FAIL); 2046 } 2047 /* 2048 * Check to see if the document was removed whilst waiting for 2049 * the lock. If it was return an error. 2050 */ 2051 if (stat(conf->pc_location, &s) == -1) { 2052 (void) fclose(prov->pxc_file); 2053 prov->pxc_file = NULL; 2054 pool_seterror(POE_SYSTEM); 2055 return (PO_FAIL); 2056 } 2057 /* Parse the document */ 2058 if (pool_xml_parse_document(conf) != PO_SUCCESS) 2059 return (PO_FAIL); 2060 return (PO_SUCCESS); 2061 } 2062 2063 /* 2064 * Try to work out if an element contains an attribute of the supplied name. 2065 * Search the internal subset first and then the external subset. 2066 * Return PO_TRUE if there is an attribute of that name declared for that 2067 * element. 2068 */ 2069 int 2070 pool_is_xml_attr(xmlDocPtr doc, const char *elem, const char *attr) 2071 { 2072 xmlDtdPtr internal = xmlGetIntSubset(doc); 2073 xmlDtdPtr external = doc->extSubset; 2074 2075 if (xmlGetDtdAttrDesc(internal, BAD_CAST elem, BAD_CAST attr) == NULL) 2076 if (xmlGetDtdAttrDesc(external, 2077 BAD_CAST elem, BAD_CAST attr) == NULL) 2078 return (PO_FALSE); 2079 return (PO_TRUE); 2080 } 2081 2082 /* 2083 * Execute the specified query using XPath. This complex function relies on 2084 * a couple of helpers to build up an XPath query, pool_build_xpath_buf in 2085 * particular. 2086 * conf - the pool configuration being manipulated 2087 * src - the root of the search, if NULL that means whole document 2088 * src_attr - if supplied means an IDREF(S) search on this attribute 2089 * classes - target classes 2090 * props - target properties 2091 * Returns pool_result_set_t pointer/NULL 2092 */ 2093 pool_result_set_t * 2094 pool_xml_exec_query(const pool_conf_t *conf, const pool_elem_t *src, 2095 const char *src_attr, pool_elem_class_t classes, pool_value_t **props) 2096 { 2097 char *buf = NULL; 2098 char_buf_t *cb = NULL; 2099 pool_xml_result_set_t *rs; 2100 pool_xml_elem_t *pxe = (pool_xml_elem_t *)src; 2101 pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; 2102 2103 if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) 2104 return (NULL); 2105 2106 /* 2107 * Prior to building up the complex XPath query, check to see if 2108 * src_attr is an IDREF(S). If it is use the IDREF(S) information 2109 * to generate the query rather than the other data 2110 */ 2111 if (src_attr != NULL) { 2112 char *tok; 2113 char *lasts; 2114 char *or = ""; 2115 xmlChar *id; 2116 2117 /* 2118 * Check the arguments for consistency 2119 */ 2120 if (pool_is_xml_attr(prov->pxc_doc, 2121 element_class_tags[src->pe_class], src_attr) != PO_TRUE) { 2122 free_char_buf(cb); 2123 pool_seterror(POE_BADPARAM); 2124 return (NULL); 2125 } 2126 2127 if ((id = xmlGetProp(pxe->pxe_node, BAD_CAST src_attr)) 2128 == NULL) { 2129 free_char_buf(cb); 2130 pool_seterror(POE_DATASTORE); 2131 return (NULL); 2132 } 2133 for (tok = strtok_r((char *)id, " ", &lasts); 2134 tok != NULL; tok = strtok_r(NULL, " ", &lasts)) { 2135 (void) append_char_buf(cb, "%s//*[@ref_id=\"%s\"]", 2136 or, tok); 2137 or = " | "; 2138 if ((classes & PEC_QRY_SYSTEM) != 0) { 2139 if (pool_build_xpath_buf(prov, src, PEC_SYSTEM, 2140 props, cb, PO_TRUE) == PO_FAIL) { 2141 free_char_buf(cb); 2142 return (NULL); 2143 } 2144 } 2145 if ((classes & PEC_QRY_POOL) != 0) { 2146 if (pool_build_xpath_buf(prov, src, PEC_POOL, 2147 props, cb, PO_TRUE) == PO_FAIL) { 2148 free_char_buf(cb); 2149 return (NULL); 2150 } 2151 } 2152 if ((classes & PEC_QRY_RES_COMP) != 0) { 2153 if (pool_build_xpath_buf(prov, src, 2154 PEC_RES_COMP, props, cb, PO_TRUE) 2155 == PO_FAIL) { 2156 free_char_buf(cb); 2157 return (NULL); 2158 } 2159 } else if ((classes & PEC_QRY_RES_AGG) != 0) { 2160 if (pool_build_xpath_buf(prov, src, 2161 PEC_RES_AGG, props, cb, PO_TRUE) 2162 == PO_FAIL) { 2163 free_char_buf(cb); 2164 return (NULL); 2165 } 2166 } 2167 } 2168 xmlFree(id); 2169 } else { 2170 /* 2171 * Build up an XPath query using the supplied parameters. 2172 * The basic logic is to: 2173 * - Identify which classes are the targets of the query 2174 * - For each class work out if the props are attributes or not 2175 * - Build up a piece of XPath for each class 2176 * - Combine the results into one large XPath query. 2177 * - Execute the query. 2178 */ 2179 if ((classes & PEC_QRY_SYSTEM) != 0) { 2180 if (pool_build_xpath_buf(prov, src, PEC_SYSTEM, props, 2181 cb, PO_FALSE) == PO_FAIL) { 2182 free_char_buf(cb); 2183 return (NULL); 2184 } 2185 } 2186 if ((classes & PEC_QRY_POOL) != 0) { 2187 if (pool_build_xpath_buf(prov, src, PEC_POOL, props, 2188 cb, PO_FALSE) == PO_FAIL) { 2189 free_char_buf(cb); 2190 return (NULL); 2191 } 2192 } 2193 if ((classes & PEC_QRY_RES_COMP) != 0) { 2194 if (pool_build_xpath_buf(prov, src, PEC_RES_COMP, props, 2195 cb, PO_FALSE) == PO_FAIL) { 2196 free_char_buf(cb); 2197 return (NULL); 2198 } 2199 } 2200 if ((classes & PEC_QRY_RES_AGG) != 0) { 2201 if (pool_build_xpath_buf(prov, src, PEC_RES_AGG, props, 2202 cb, PO_FALSE) == PO_FAIL) { 2203 free_char_buf(cb); 2204 return (NULL); 2205 } 2206 } 2207 if ((classes & PEC_QRY_COMP) != 0) { 2208 if (pool_build_xpath_buf(prov, src, PEC_COMP, props, 2209 cb, PO_FALSE) == PO_FAIL) { 2210 free_char_buf(cb); 2211 return (NULL); 2212 } 2213 } 2214 } 2215 buf = strdup(cb->cb_buf); 2216 free_char_buf(cb); 2217 /* 2218 * Have a buffer at this point, that we can use 2219 */ 2220 if ((rs = pool_xml_result_set_alloc(conf)) == NULL) { 2221 free(buf); 2222 return (NULL); 2223 } 2224 /* 2225 * Set up the XPath Query 2226 */ 2227 if ((rs->pxr_ctx = xmlXPathNewContext( 2228 ((pool_xml_connection_t *)conf->pc_prov)->pxc_doc)) == NULL) { 2229 free(buf); 2230 (void) pool_xml_rs_close((pool_result_set_t *)rs); 2231 pool_seterror(POE_DATASTORE); 2232 return (NULL); 2233 } 2234 if (src == NULL) 2235 rs->pxr_ctx->node = xmlDocGetRootElement 2236 (((pool_xml_connection_t *)conf->pc_prov)->pxc_doc); 2237 else 2238 rs->pxr_ctx->node = pxe->pxe_node; 2239 /* 2240 * Select 2241 */ 2242 rs->pxr_path = xmlXPathEval(BAD_CAST buf, rs->pxr_ctx); 2243 free(buf); 2244 /* 2245 * Generate the result set and wrap the results as pool_elem_t 2246 */ 2247 if (rs->pxr_path->nodesetval->nodeNr == 0) 2248 pool_seterror(POE_INVALID_SEARCH); 2249 return ((pool_result_set_t *)rs); 2250 } 2251 2252 /* 2253 * Build an XPath query buffer. This is complex and a little fragile, but 2254 * I'm trying to accomplish something complex with as little code as possible. 2255 * I wait the implementation of XMLQuery with baited breath... 2256 * Returns PO_SUCCESS/PO_FAIL 2257 */ 2258 static int 2259 pool_build_xpath_buf(pool_xml_connection_t *prov, const pool_elem_t *src, 2260 pool_elem_class_t class, pool_value_t *props[], char_buf_t *cb, int is_ref) 2261 { 2262 int i; 2263 const char *ATTR_FMTS[] = { 2264 "[ @%s=\"%llu\" ]", /* POC_UINT */ 2265 "[ @%s=\"%lld\" ]", /* POC_INT */ 2266 "[ @%s=\"%f\" ]", /* POC_DOUBLE */ 2267 "[ @%s=\"%s\" ]", /* POC_BOOL */ 2268 "[ @%s=\"%s\" ]", /* POC_STRING */ 2269 }; 2270 const char *PROP_FMTS[] = { 2271 "[ property[@name=\"%s\"][text()=\"%llu\"] ]", /* POC_UINT */ 2272 "[ property[@name=\"%s\"][text()=\"%lld\"] ]", /* POC_INT */ 2273 "[ property[@name=\"%s\"][text()=\"%f\"] ]", /* POC_DOUBLE */ 2274 "[ property[@name=\"%s\"][text()=\"%s\"] ]", /* POC_BOOL */ 2275 "[ property[@name=\"%s\"][text()=\"%s\"] ]" /* POC_STRING */ 2276 }; 2277 const char **fmts; 2278 int nprop; 2279 const char *last_prop_name = NULL; 2280 char *type_prefix = NULL; 2281 int has_type = PO_FALSE; 2282 2283 if (is_ref == PO_FALSE) { 2284 if (cb->cb_buf != NULL && strlen(cb->cb_buf) > 0) 2285 (void) append_char_buf(cb, " |"); 2286 if (src != NULL) 2287 (void) append_char_buf(cb, " ./"); 2288 else 2289 (void) append_char_buf(cb, "//"); 2290 (void) append_char_buf(cb, element_class_tags[class]); 2291 } 2292 if (props == NULL || props[0] == NULL) 2293 return (PO_SUCCESS); 2294 for (nprop = 0; props[nprop] != NULL; nprop++) 2295 /* Count properties */; 2296 /* 2297 * Sort the attributes and properties by name. 2298 */ 2299 qsort(props, nprop, sizeof (pool_value_t *), prop_sort); 2300 for (i = 0; i < nprop; i++) { 2301 int is_attr = 0; 2302 const char *prefix; 2303 const char *prop_name; 2304 uint64_t uval; 2305 int64_t ival; 2306 double dval; 2307 uchar_t bval; 2308 const char *sval; 2309 pool_value_class_t pvc; 2310 2311 prop_name = pool_value_get_name(props[i]); 2312 if ((prefix = is_a_known_prefix(class, prop_name)) != NULL) { 2313 const char *attr_name; 2314 /* 2315 * Possibly an attribute. Strip off the prefix. 2316 */ 2317 if (strcmp(prop_name, c_type) == 0) { 2318 has_type = PO_TRUE; 2319 attr_name = prop_name; 2320 } else 2321 attr_name = prop_name + strlen(prefix) + 1; 2322 if (pool_is_xml_attr(prov->pxc_doc, 2323 element_class_tags[class], attr_name)) { 2324 is_attr = 1; 2325 prop_name = attr_name; 2326 if (class == PEC_RES_COMP || 2327 class == PEC_RES_AGG || 2328 class == PEC_COMP) { 2329 if (type_prefix != NULL) 2330 free(type_prefix); 2331 type_prefix = strdup(prefix); 2332 } 2333 } 2334 } 2335 if (is_attr) { 2336 fmts = ATTR_FMTS; 2337 } else { 2338 fmts = PROP_FMTS; 2339 } 2340 /* 2341 * Add attributes/properties to the search buffer 2342 */ 2343 switch ((pvc = pool_value_get_type(props[i]))) { 2344 case POC_UINT: 2345 (void) pool_value_get_uint64(props[i], &uval); 2346 if (append_char_buf(cb, fmts[pvc], prop_name, uval) 2347 == PO_FAIL) { 2348 free(type_prefix); 2349 return (PO_FAIL); 2350 } 2351 break; 2352 case POC_INT: 2353 (void) pool_value_get_int64(props[i], &ival); 2354 if (append_char_buf(cb, fmts[pvc], prop_name, ival) 2355 == PO_FAIL) { 2356 free(type_prefix); 2357 return (PO_FAIL); 2358 } 2359 break; 2360 case POC_DOUBLE: 2361 (void) pool_value_get_double(props[i], &dval); 2362 if (append_char_buf(cb, fmts[pvc], prop_name, dval) 2363 == PO_FAIL) { 2364 free(type_prefix); 2365 return (PO_FAIL); 2366 } 2367 break; 2368 case POC_BOOL: 2369 (void) pool_value_get_bool(props[i], &bval); 2370 if (append_char_buf(cb, fmts[pvc], prop_name, 2371 bval ? "true" : "false") == PO_FAIL) { 2372 free(type_prefix); 2373 return (PO_FAIL); 2374 } 2375 break; 2376 case POC_STRING: 2377 (void) pool_value_get_string(props[i], &sval); 2378 if (append_char_buf(cb, fmts[pvc], prop_name, sval) 2379 == PO_FAIL) { 2380 free(type_prefix); 2381 return (PO_FAIL); 2382 } 2383 break; 2384 default: 2385 free(type_prefix); 2386 pool_seterror(POE_INVALID_SEARCH); 2387 return (PO_FAIL); 2388 } 2389 if (last_prop_name != NULL) { 2390 const char *suffix1, *suffix2; 2391 /* 2392 * Extra fiddling for namespaces 2393 */ 2394 suffix1 = strrchr(prop_name, '.'); 2395 suffix2 = strrchr(last_prop_name, '.'); 2396 2397 if (suffix1 != NULL || suffix2 != NULL) { 2398 if (suffix1 == NULL) 2399 suffix1 = prop_name; 2400 else 2401 suffix1++; 2402 if (suffix2 == NULL) 2403 suffix2 = last_prop_name; 2404 else 2405 suffix2++; 2406 } else { 2407 suffix1 = prop_name; 2408 suffix2 = last_prop_name; 2409 } 2410 if (strcmp(suffix1, suffix2) == 0) { 2411 char *where = strrchr(cb->cb_buf, '['); 2412 if (is_attr != PO_TRUE) { 2413 /* repeat */ 2414 while (*--where != '[') 2415 ; 2416 while (*--where != '[') 2417 ; 2418 } 2419 *(where - 1) = 'o'; 2420 *where = 'r'; 2421 } 2422 } 2423 last_prop_name = prop_name; 2424 } 2425 if (has_type == PO_FALSE) { 2426 if (type_prefix) { 2427 if (append_char_buf(cb, ATTR_FMTS[POC_STRING], 2428 c_type, type_prefix) == PO_FAIL) { 2429 free(type_prefix); 2430 return (PO_FAIL); 2431 } 2432 } 2433 } 2434 free(type_prefix); 2435 return (PO_SUCCESS); 2436 } 2437 2438 /* 2439 * Utility routine for use by quicksort. Assumes that the supplied data 2440 * are pool values and compares the names of the two pool values. 2441 * Returns an integer greater than, equal to, or less than 0. 2442 */ 2443 static int 2444 prop_sort(const void *a, const void *b) 2445 { 2446 pool_value_t **prop_a = (pool_value_t **)a; 2447 pool_value_t **prop_b = (pool_value_t **)b; 2448 const char *str_a; 2449 const char *str_b; 2450 const char *suffix1, *suffix2; 2451 2452 str_a = pool_value_get_name(*prop_a); 2453 str_b = pool_value_get_name(*prop_b); 2454 /* 2455 * Extra fiddling for namespaces 2456 */ 2457 suffix1 = strrchr(str_a, '.'); 2458 suffix2 = strrchr(str_b, '.'); 2459 2460 if (suffix1 != NULL || suffix2 != NULL) { 2461 if (suffix1 == NULL) 2462 suffix1 = str_a; 2463 else 2464 suffix1++; 2465 if (suffix2 == NULL) 2466 suffix2 = str_b; 2467 else 2468 suffix2++; 2469 } else { 2470 suffix1 = str_a; 2471 suffix2 = str_b; 2472 } 2473 return (strcmp(suffix1, suffix2)); 2474 } 2475 2476 /* 2477 * Order the elements by (ref_id) 2478 */ 2479 2480 /* 2481 * Returns PO_TRUE/PO_FALSE to indicate whether the supplied path exists on the 2482 * system. It is assumed that the supplied path is in URL format and represents 2483 * a file and so file:// is stripped from the start of the search. 2484 */ 2485 static int 2486 dtd_exists(const char *path) 2487 { 2488 struct stat buf; 2489 2490 if (strstr(path, "file://") != path) 2491 return (PO_FALSE); 2492 2493 if (path[7] == 0) 2494 return (PO_FALSE); 2495 2496 if (stat(&path[7], &buf) == 0) 2497 return (PO_TRUE); 2498 return (PO_FALSE); 2499 } 2500 2501 /* 2502 * Build the dtype structures to accelerate data type lookup operations. The 2503 * purpose is to avoid expensive XML manipulations on data which will not 2504 * change over the life of a library invocation. It is designed to be invoked 2505 * once from the library init function. 2506 */ 2507 static void 2508 build_dtype_accelerator(void) 2509 { 2510 xmlDtdPtr dtd; 2511 const xmlChar *elem_list[ELEM_TYPE_COUNT] = { 2512 BAD_CAST "res_comp", 2513 BAD_CAST "res_agg", 2514 BAD_CAST "comp", 2515 BAD_CAST "pool", 2516 BAD_CAST "property", 2517 BAD_CAST "system" }; 2518 int i; 2519 2520 if (_libpool_xml_initialised == PO_TRUE) 2521 return; 2522 2523 /* Load up the d-type data for each element */ 2524 /* 2525 * Store data type information in nested lists 2526 * Top level list contains attribute declaration pointers which 2527 * can be used to match with supplied nodes. 2528 * Second level list contains attribute type information for each 2529 * element declaration 2530 */ 2531 /* 2532 * Unfortunately, there's no easy way to get a list of all DTD 2533 * element descriptions as there is no libxml API to do this (they 2534 * are stored in a hash, which I guess is why). Explicitly seek 2535 * for descriptions for elements that are known to hold an a-dtype 2536 * attribute and build accelerators for those elements. 2537 * If the DTD changes, the library may have to change as well now, 2538 * since this code makes explicit assumptions about which elements 2539 * contain a-dtype information. 2540 */ 2541 2542 if ((dtd = xmlParseDTD(BAD_CAST "-//Sun Microsystems Inc//DTD Resource" 2543 " Management All//EN", BAD_CAST dtd_location)) == NULL) 2544 return; 2545 for (i = 0; i < ELEM_TYPE_COUNT; i++) { 2546 xmlElementPtr elem; 2547 xmlAttributePtr attr; 2548 2549 if ((elem = xmlGetDtdElementDesc(dtd, elem_list[i])) == NULL) 2550 return; 2551 elem_tbl[i].ett_elem = xmlStrdup(elem->name); 2552 /* Walk the list of attributes looking for a-dtype */ 2553 for (attr = elem->attributes; attr != NULL; 2554 attr = attr->nexth) { 2555 if (strcmp((const char *)attr->name, c_a_dtype) == 0) { 2556 /* 2557 * Allocate a dtype_tbl_t 2558 */ 2559 elem_tbl[i].ett_dtype = 2560 build_dtype_tbl(attr->defaultValue); 2561 /* This could have returned NULL */ 2562 } 2563 } 2564 } 2565 xmlFreeDtd(dtd); 2566 } 2567 2568 /* 2569 * build_dtype_tbl() parses the supplied data and returns an array (max size 2570 * of 10, increase if required) of dtype_tbl_t structures holding data type 2571 * information for an element. The supplied data is assumed to be in "a-dtype" 2572 * format. The dtype_tbl_t array is NULL terminated, which is why space for 2573 * 11 members is allocated. 2574 */ 2575 static dtype_tbl_t 2576 (*build_dtype_tbl(const xmlChar *rawdata))[] 2577 { 2578 char *tok; 2579 char *lasts; 2580 dtype_tbl_t (*tbl)[]; 2581 int j = 0; 2582 xmlChar *data; 2583 const int max_attr = 11; /* Not more than 10 types per element */ 2584 2585 /* 2586 * Parse the supplied data, assumed to be in a-dtype format, and 2587 * generate a lookup table which is indexed by the name and contains 2588 * the data type 2589 */ 2590 if (rawdata == NULL) 2591 return (NULL); 2592 if ((data = xmlStrdup(rawdata)) == NULL) 2593 return (NULL); 2594 if ((tbl = calloc(max_attr, sizeof (dtype_tbl_t))) == NULL) { 2595 xmlFree(data); 2596 return (NULL); 2597 } 2598 for (tok = strtok_r((char *)data, " ", &lasts); tok != NULL; 2599 tok = strtok_r(NULL, " ", &lasts)) { 2600 int i; 2601 (*tbl)[j].dt_name = xmlStrdup(BAD_CAST tok); 2602 if ((tok = strtok_r(NULL, " ", &lasts)) == NULL) { 2603 int k = j; 2604 for (j = 0; j < k; j++) 2605 free((*tbl)[j].dt_name); 2606 pool_seterror(POE_DATASTORE); 2607 xmlFree(data); 2608 free(tbl); 2609 return (NULL); 2610 } 2611 for (i = 0; i < (sizeof (data_type_tags) / 2612 sizeof (data_type_tags[0])); i++) { 2613 if (strcmp(tok, data_type_tags[i]) == 0) 2614 (*tbl)[j++].dt_type = i; 2615 } 2616 if (j == max_attr) { /* too many attributes, bail out */ 2617 for (j = 0; j < max_attr; j++) 2618 free((*tbl)[j].dt_name); 2619 free(tbl); 2620 xmlFree(data); 2621 return (NULL); 2622 } 2623 } 2624 (*tbl)[j].dt_name = NULL; /* Terminate the table */ 2625 xmlFree(data); 2626 return (tbl); 2627 } 2628 2629 /* 2630 * get_fast_dtype() finds the data type for a supplied attribute name on a 2631 * supplied node. This is called get_fast_dtype() because it uses the cached 2632 * data type information created at library initialisation. 2633 */ 2634 static int 2635 get_fast_dtype(xmlNodePtr node, xmlChar *name) 2636 { 2637 int i; 2638 xmlElementPtr elem; 2639 2640 if ((elem = xmlGetDtdElementDesc(node->doc->extSubset, node->name)) 2641 == NULL) { 2642 pool_seterror(POE_BADPARAM); 2643 return (POC_INVAL); 2644 } 2645 2646 for (i = 0; i < ELEM_TYPE_COUNT; i++) { 2647 if (xmlStrcmp(elem_tbl[i].ett_elem, elem->name) == 0) { 2648 dtype_tbl_t (*tbl)[] = elem_tbl[i].ett_dtype; 2649 int j = 0; 2650 2651 if (tbl == NULL) 2652 break; 2653 for (j = 0; (*tbl)[j].dt_name != NULL; j++) 2654 if (xmlStrcmp(name, (*tbl)[j].dt_name) == 0) 2655 return ((*tbl)[j].dt_type); /* found */ 2656 break; /* if we didn't find it in the elem, break */ 2657 } 2658 } 2659 /* If we can't find it, say it's a string */ 2660 return (POC_STRING); 2661 } 2662 2663 /* 2664 * pool_xml_parse_document() parses the file associated with a supplied 2665 * configuration to regenerate the runtime representation. The supplied 2666 * configuration must reference an already opened file and this is used 2667 * to generate the XML representation via the configuration provider's 2668 * pxc_doc member. 2669 * size must be >=4 in order for "content encoding detection" to work. 2670 */ 2671 static int 2672 pool_xml_parse_document(pool_conf_t *conf) 2673 { 2674 int res; 2675 char chars[PAGE_READ_SIZE]; 2676 struct stat f_stat; 2677 xmlParserCtxtPtr ctxt; 2678 size_t size; 2679 pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov; 2680 xmlNodePtr root; 2681 pool_resource_t **rsl; 2682 uint_t nelem; 2683 int i; 2684 2685 if (fstat(fileno(prov->pxc_file), &f_stat) == -1) { 2686 pool_seterror(POE_SYSTEM); 2687 return (PO_FAIL); 2688 } 2689 2690 if (f_stat.st_size == 0) { 2691 pool_seterror(POE_INVALID_CONF); 2692 return (PO_FAIL); 2693 } else 2694 size = f_stat.st_size < 4 ? 4 : PAGE_READ_SIZE; 2695 2696 res = fread(chars, 1, size, prov->pxc_file); 2697 2698 if (res >= 4) { 2699 xmlValidCtxtPtr cvp; 2700 2701 if ((ctxt = xmlCreatePushParserCtxt(NULL, NULL, 2702 chars, res, conf->pc_location)) == NULL) { 2703 pool_seterror(POE_INVALID_CONF); 2704 return (PO_FAIL); 2705 } 2706 2707 while ((res = fread(chars, 1, size, prov->pxc_file)) > 0) { 2708 if (xmlParseChunk(ctxt, chars, res, 0) != 0) { 2709 xmlFreeParserCtxt(ctxt); 2710 pool_seterror(POE_INVALID_CONF); 2711 return (PO_FAIL); 2712 } 2713 } 2714 if (xmlParseChunk(ctxt, chars, 0, 1) != 0) { 2715 xmlFreeParserCtxt(ctxt); 2716 pool_seterror(POE_INVALID_CONF); 2717 return (PO_FAIL); 2718 } 2719 2720 if ((cvp = xmlNewValidCtxt()) == NULL) { 2721 pool_seterror(POE_INVALID_CONF); 2722 return (PO_FAIL); 2723 } 2724 cvp->error = pool_error_func; 2725 cvp->warning = pool_error_func; 2726 2727 if (xmlValidateDocument(cvp, ctxt->myDoc) == 0) { 2728 xmlFreeValidCtxt(cvp); 2729 xmlFreeParserCtxt(ctxt); 2730 pool_seterror(POE_INVALID_CONF); 2731 return (PO_FAIL); 2732 } 2733 prov->pxc_doc = ctxt->myDoc; 2734 xmlFreeValidCtxt(cvp); 2735 xmlFreeParserCtxt(ctxt); 2736 } 2737 if (prov->pxc_doc == NULL) { 2738 pool_seterror(POE_INVALID_CONF); 2739 return (PO_FAIL); 2740 } 2741 prov->pxc_doc->_private = conf; 2742 2743 /* Get the root element */ 2744 if ((root = xmlDocGetRootElement(prov->pxc_doc)) == NULL) { 2745 pool_seterror(POE_INVALID_CONF); 2746 return (PO_FAIL); 2747 } 2748 /* 2749 * Ensure that the parsed tree has been contained within 2750 * our shadow tree. 2751 */ 2752 if (create_shadow(root) != PO_SUCCESS) { 2753 pool_seterror(POE_INVALID_CONF); 2754 return (PO_FAIL); 2755 } 2756 2757 if (pool_xml_validate(conf, POV_STRICT) != PO_SUCCESS) { 2758 return (PO_FAIL); 2759 } 2760 /* 2761 * For backwards compatibility with S9, make sure that all 2762 * resources have a size and that it is correct. 2763 */ 2764 if ((rsl = pool_query_resources(conf, &nelem, NULL)) != NULL) { 2765 pool_value_t val = POOL_VALUE_INITIALIZER; 2766 for (i = 0; i < nelem; i++) { 2767 if (pool_get_ns_property(TO_ELEM(rsl[i]), c_size_prop, 2768 &val) != POC_UINT) { 2769 pool_component_t **cs; 2770 uint_t size; 2771 if ((cs = pool_query_resource_components(conf, 2772 rsl[i], &size, NULL)) != NULL) { 2773 free(cs); 2774 pool_value_set_uint64(&val, size); 2775 } else 2776 pool_value_set_uint64(&val, 0); 2777 if (pool_put_any_ns_property(TO_ELEM(rsl[i]), 2778 c_size_prop, &val) != PO_SUCCESS) { 2779 free(rsl); 2780 return (PO_FAIL); 2781 } 2782 } 2783 } 2784 free(rsl); 2785 } 2786 return (PO_SUCCESS); 2787 } 2788