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