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