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