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