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