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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
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>
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
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).
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
102 typedef struct elem_type_tbl
105 dtype_tbl_t (*ett_dtype
)[];
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
[] = {
126 static const char *data_type_tags
[] = {
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
;
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.
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
);
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
*,
184 static int pool_xml_res_xtransfer(pool_resource_t
*, pool_resource_t
*,
185 pool_component_t
**);
188 static void pool_xml_connection_free(pool_xml_connection_t
*prov
);
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
*);
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 *,
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
258 (void) mutex_lock(&_xml_lock
);
259 if (_libpool_xml_initialised
== PO_TRUE
) {
260 (void) mutex_unlock(&_xml_lock
);
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
285 get_unique_id(xmlNodePtr node
, char *id
)
287 pool_value_t val
= POOL_VALUE_INITIALIZER
;
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
);
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",
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.
313 node_create(xmlNodePtr parent
, const xmlChar
*name
)
318 node
= xmlNewNode(NULL
, name
);
320 node
= xmlNewChild(parent
, NULL
, name
, NULL
);
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.
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
);
336 if (get_unique_id(node
, id
) != PO_SUCCESS
) {
338 xmlFreeNode(node
); /* recurses all children */
339 pool_seterror(POE_DATASTORE
);
342 if (xmlSetProp(node
, BAD_CAST c_ref_id
, BAD_CAST id
) == NULL
) {
344 xmlFreeNode(node
); /* recurses all children */
345 pool_seterror(POE_DATASTORE
);
352 /* Supporting Data Conversion Routines */
354 /* XML Parser Utility Functions */
357 * Handler for XML Errors. Called by libxml at libxml Error.
361 pool_error_func(void *ctx
, const char *msg
, ...)
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
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
) {
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
);
386 pool_seterror(POE_INVALID_CONF
);
389 for (pe
= rs
->prs_next(rs
); pe
!= NULL
; pe
= rs
->prs_next(rs
)) {
391 * Work out the element type and free the elem
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
;
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
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
417 switch (pe
->pe_class
) {
423 xmlUnlinkNode(pxe
->pxe_node
);
424 xmlFreeNode(pxe
->pxe_node
); /* recurses all children */
435 * Create a property element.
438 property_create(xmlNodePtr parent
, const char *name
, pool_value_class_t type
)
442 pool_value_t val
= POOL_VALUE_INITIALIZER
;
444 if ((element
= node_create(parent
, BAD_CAST
"property")) == NULL
) {
445 pool_seterror(POE_DATASTORE
);
448 if (pool_value_set_string(&val
, name
) != PO_SUCCESS
) {
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
) {
457 (void) pool_xml_set_attr(element
, BAD_CAST c_type
, &val
);
462 * External clients need to be able to put/get properties and this is the
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
,
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
,
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
))
487 return (pool_xml_get_prop(pxe
->pxe_node
, BAD_CAST name
,
490 return (pool_xml_get_prop(pxe
->pxe_node
, BAD_CAST name
, val
));
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:
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
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
,
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
,
526 return (pool_xml_set_prop(pxe
->pxe_node
, BAD_CAST name
, val
));
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
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
];
544 if (xmlHasProp(pxe
->pxe_node
, BAD_CAST name
) != NULL
) {
545 pool_seterror(POE_BADPARAM
);
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
);
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]);
564 pool_seterror(POE_BADPARAM
);
567 xmlXPathFreeObject(path
);
568 xmlXPathFreeContext(ctx
);
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
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
;
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
);
590 if (xmlHasProp(node
, BAD_CAST c_a_dtype
) == NULL
) {
591 pool_seterror(POE_INVALID_CONF
);
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
);
603 uval
= strtoull((char *)data
, NULL
, 0);
605 data_type
= POC_INVAL
;
608 pool_value_set_uint64(value
, uval
);
612 ival
= strtoll((char *)data
, NULL
, 0);
614 data_type
= POC_INVAL
;
617 pool_value_set_int64(value
, ival
);
620 pool_value_set_double(value
, atof((const char *)data
));
623 if (strcmp((const char *)data
, "true") == 0)
624 pool_value_set_bool(value
, PO_TRUE
);
626 pool_value_set_bool(value
, PO_FALSE
);
629 if (pool_value_set_string(value
, data
?
630 (const char *)data
: "") != PO_SUCCESS
) {
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
649 pool_xml_set_attr(xmlNodePtr node
, xmlChar
*name
, const pool_value_t
*value
)
651 xmlChar buf
[MAX_PROP_SIZE
] = {0};
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
);
666 if (xmlHasProp(node
, BAD_CAST c_a_dtype
) == NULL
) {
667 pool_seterror(POE_INVALID_CONF
);
670 data_type
= get_fast_dtype(node
, name
);
671 if (data_type
!= value
->pv_class
) {
672 pool_seterror(POE_BADPARAM
);
675 switch (value
->pv_class
) {
677 (void) pool_value_get_uint64(value
, &ures
);
678 (void) snprintf((char *)buf
, sizeof (buf
), "%llu",
682 (void) pool_value_get_int64(value
, &ires
);
683 (void) snprintf((char *)buf
, sizeof (buf
), "%lld",
687 (void) pool_value_get_double(value
, &dres
);
688 (void) snprintf((char *)buf
, sizeof (buf
), "%f", dres
);
691 (void) pool_value_get_bool(value
, &bres
);
692 if (bres
== PO_FALSE
)
693 (void) snprintf((char *)buf
, sizeof (buf
),
696 (void) snprintf((char *)buf
, sizeof (buf
),
700 (void) pool_value_get_string(value
, &sres
);
702 (void) snprintf((char *)buf
, sizeof (buf
), "%s",
709 if (xmlSetProp(node
, name
, buf
) == NULL
) {
710 pool_seterror(POE_DATASTORE
);
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
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
];
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
);
740 path
= xmlXPathEval(BAD_CAST buf
, ctx
);
742 if (path
&& (path
->type
== XPATH_NODESET
) &&
743 (path
->nodesetval
->nodeNr
== 1)) {
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
);
752 /* type is a string representation of the type */
753 data
= xmlGetProp(path
->nodesetval
->nodeTab
[0],
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) {
767 uval
= strtoull((char *)node_data
, NULL
, 0);
769 data_type
= POC_INVAL
;
771 pool_value_set_uint64(value
, uval
);
775 ival
= strtoll((char *)node_data
, NULL
, 0);
777 data_type
= POC_INVAL
;
779 pool_value_set_int64(value
, ival
);
782 pool_value_set_double(value
,
783 atof((const char *)node_data
));
786 if (strcmp((const char *)node_data
, "true")
788 pool_value_set_bool(value
, PO_TRUE
);
790 pool_value_set_bool(value
, PO_FALSE
);
793 if (pool_value_set_string(value
,
794 (const char *)node_data
) != PO_SUCCESS
) {
795 data_type
= POC_INVAL
;
805 xmlXPathFreeObject(path
);
806 xmlXPathFreeContext(ctx
);
808 } else { /* No property exists, clean up and return */
809 xmlXPathFreeObject(path
);
810 xmlXPathFreeContext(ctx
);
811 pool_seterror(POE_BADPARAM
);
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
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
];
835 /* use xpath to find the node with the appropriate value for name */
836 (void) snprintf((char *)buf
, sizeof (buf
), "property[@name=\"%s\"]",
838 if ((ctx
= xmlXPathNewContext(node
->doc
)) == NULL
) {
839 pool_seterror(POE_BADPARAM
);
843 path
= xmlXPathEval(buf
, ctx
);
844 if (path
== NULL
|| path
->type
!= XPATH_NODESET
) {
845 xmlXPathFreeObject(path
);
846 xmlXPathFreeContext(ctx
);
847 pool_seterror(POE_BADPARAM
);
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) {
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
);
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
])
872 if (value
->pv_class
!= i
) {
873 xmlXPathFreeObject(path
);
874 xmlXPathFreeContext(ctx
);
875 pool_seterror(POE_BADPARAM
);
879 xmlXPathFreeObject(path
);
880 xmlXPathFreeContext(ctx
);
881 pool_seterror(POE_BADPARAM
);
886 switch (value
->pv_class
) {
888 (void) pool_value_get_uint64(value
, &ures
);
889 (void) snprintf((char *)buf
, sizeof (buf
), "%llu",
893 (void) pool_value_get_int64(value
, &ires
);
894 (void) snprintf((char *)buf
, sizeof (buf
), "%lld",
898 (void) pool_value_get_double(value
, &dres
);
899 (void) snprintf((char *)buf
, sizeof (buf
), "%f", dres
);
902 (void) pool_value_get_bool(value
, &bres
);
903 if (bres
== PO_FALSE
)
904 (void) snprintf((char *)buf
, sizeof (buf
),
907 (void) snprintf((char *)buf
, sizeof (buf
),
911 (void) pool_value_get_string(value
, &sres
);
912 (void) snprintf((char *)buf
, sizeof (buf
), "%s", sres
);
918 xmlNodeSetContent(element
, buf
);
919 xmlXPathFreeObject(path
);
920 xmlXPathFreeContext(ctx
);
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.
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
;
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
;
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)
953 if ((ctx
= xmlXPathNewContext(
954 ((pool_xml_connection_t
*)conf
->pc_prov
)->pxc_doc
)) == NULL
) {
955 pool_seterror(POE_BADPARAM
);
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
);
971 if ((cb
= alloc_char_buf(CB_DEFAULT_LEN
)) == NULL
) {
972 xmlXPathFreeObject(path
);
973 xmlXPathFreeContext(ctx
);
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) {
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
);
993 pool_value_free(result
[i
]);
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
) !=
1002 xmlXPathFreeObject(path
);
1003 xmlXPathFreeContext(ctx
);
1005 pool_value_free(result
[i
]);
1010 if (pool_value_set_name(result
[i
], cb
->cb_buf
) !=
1012 xmlXPathFreeObject(path
);
1013 xmlXPathFreeContext(ctx
);
1015 pool_value_free(result
[i
]);
1021 if (pool_value_set_name(result
[i
],
1022 (const char *)attr
->name
) != PO_SUCCESS
) {
1023 xmlXPathFreeObject(path
);
1024 xmlXPathFreeContext(ctx
);
1026 pool_value_free(result
[i
]);
1034 for (j
= 0; j
< path
->nodesetval
->nodeNr
; j
++, i
++) {
1035 xmlChar
*name
= xmlGetProp(path
->nodesetval
->nodeTab
[j
],
1038 result
[i
] = pool_value_alloc();
1040 if (pool_xml_get_prop(pxe
->pxe_node
, name
, result
[i
]) ==
1043 xmlXPathFreeObject(path
);
1044 xmlXPathFreeContext(ctx
);
1046 pool_value_free(result
[i
]);
1050 if (pool_value_set_name(result
[i
], (const char *)name
) !=
1053 xmlXPathFreeObject(path
);
1054 xmlXPathFreeContext(ctx
);
1056 pool_value_free(result
[i
]);
1062 xmlXPathFreeObject(path
);
1063 xmlXPathFreeContext(ctx
);
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
1074 create_shadow(xmlNodePtr node
)
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
,
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
,
1088 } else if (0 == (xmlStrcmp(node
->name
,
1089 BAD_CAST element_class_tags
[PEC_RES_COMP
]))) {
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
);
1096 ret
= pool_xml_elem_wrap(node
, PEC_RES_COMP
, res_class
,
1098 } else if (0 == (xmlStrcmp(node
->name
,
1099 BAD_CAST element_class_tags
[PEC_RES_AGG
]))) {
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
);
1106 ret
= pool_xml_elem_wrap(node
, PEC_RES_AGG
, res_class
,
1108 } else if (0 == (xmlStrcmp(node
->name
,
1109 BAD_CAST element_class_tags
[PEC_COMP
]))) {
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(
1117 ret
= pool_xml_elem_wrap(node
, PEC_COMP
, PREC_INVALID
,
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
)
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
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
);
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
);
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
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
);
1178 /* Now close the configuration */
1179 (void) pool_conf_close(conf
);
1180 return (PO_SUCCESS
);
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
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
);
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
);
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) ==
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
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
);
1246 if (ftruncate(fileno(prov
->pxc_file
), 0) == -1) {
1247 pool_seterror(POE_SYSTEM
);
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
);
1259 if (xmlSaveFormatFileTo(buf
, prov
->pxc_doc
, NULL
, 1) == -1) {
1260 pool_seterror(POE_DATASTORE
);
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
1274 pool_xml_export(const pool_conf_t
*conf
, const char *location
,
1275 pool_export_format_t fmt
)
1281 ret
= xmlSaveFormatFile(location
,
1282 ((pool_xml_connection_t
*)conf
->pc_prov
)->pxc_doc
,
1285 pool_seterror(POE_SYSTEM
);
1288 return (PO_SUCCESS
);
1291 pool_seterror(POE_BADPARAM
);
1297 * Discard the configuration and restore the configuration to the values
1298 * specified in the configuration location.
1299 * Returns PO_SUCCESS/PO_FAIL
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
);
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
)
1316 return (PO_SUCCESS
);
1320 * Allocate a new pool_elem_t in the supplied configuration of the specified
1322 * Returns element pointer/NULL
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
);
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
1360 * Returns PO_SUCCESS/PO_FAIL
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 */
1372 if ((elem
= malloc(sizeof (pool_xml_system_t
))) == NULL
) {
1373 pool_seterror(POE_SYSTEM
);
1376 (void) memset(elem
, 0, sizeof (pool_xml_system_t
));
1379 if ((elem
= malloc(sizeof (pool_xml_pool_t
))) == NULL
) {
1380 pool_seterror(POE_SYSTEM
);
1383 (void) memset(elem
, 0, sizeof (pool_xml_pool_t
));
1387 if ((elem
= malloc(sizeof (pool_xml_resource_t
))) == NULL
) {
1388 pool_seterror(POE_SYSTEM
);
1391 (void) memset(elem
, 0, sizeof (pool_xml_resource_t
));
1394 if ((elem
= malloc(sizeof (pool_xml_component_t
))) == NULL
) {
1395 pool_seterror(POE_SYSTEM
);
1398 (void) memset(elem
, 0, sizeof (pool_xml_component_t
));
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
1412 pool_assoc_default_resource_type(pool_t
*pool
, pool_resource_elem_class_t type
)
1414 pool_value_t
*props
[] = { NULL
, NULL
, NULL
};
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
;
1426 if (pool_value_set_string(props
[0], pool_resource_type_string(type
)) !=
1428 pool_value_set_name(props
[0], c_type
) != PO_SUCCESS
) {
1432 if ((cb
= alloc_char_buf(CB_DEFAULT_LEN
)) == NULL
) {
1436 if (set_char_buf(cb
, "%s.default",
1437 pool_resource_type_string(type
)) !=
1442 if (pool_value_set_name(props
[1], cb
->cb_buf
) != PO_SUCCESS
) {
1446 pool_value_set_bool(props
[1], PO_TRUE
);
1449 if ((rsl
= pool_query_resources(conf
, &rl_size
, props
)) == NULL
) {
1450 pool_seterror(POE_INVALID_CONF
);
1455 * One default resource set per type
1459 pool_seterror(POE_INVALID_CONF
);
1462 if (pool_associate(conf
, pool
, rsl
[0]) < 0) {
1464 pool_seterror(POE_INVALID_CONF
);
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
);
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 */
1502 if ((parent_system
= pool_conf_system(conf
)) == NULL
) {
1503 pool_seterror(POE_INVALID_CONF
);
1506 if ((parent
= pool_system_elem(parent_system
)) == NULL
) {
1507 pool_seterror(POE_INVALID_CONF
);
1510 if ((elem
= malloc(sizeof (pool_xml_system_t
))) == NULL
) {
1511 pool_seterror(POE_SYSTEM
);
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
);
1525 if ((parent_system
= pool_conf_system(conf
)) == NULL
) {
1526 pool_seterror(POE_INVALID_CONF
);
1529 if ((parent
= pool_system_elem(parent_system
)) == NULL
) {
1530 pool_seterror(POE_INVALID_CONF
);
1533 if ((elem
= malloc(sizeof (pool_xml_resource_t
))) == NULL
) {
1534 pool_seterror(POE_SYSTEM
);
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
);
1547 if ((elem
= malloc(sizeof (pool_xml_component_t
))) == NULL
) {
1548 pool_seterror(POE_SYSTEM
);
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
);
1560 pool_seterror(POE_BADPARAM
);
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
);
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
);
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
);
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
1604 * Returns PO_SUCCESS/PO_FAIL
1607 pool_xml_connection_alloc(pool_conf_t
*conf
, int oflags
)
1609 pool_xml_connection_t
*prov
;
1612 if ((prov
= malloc(sizeof (pool_xml_connection_t
))) == NULL
) {
1613 pool_seterror(POE_SYSTEM
);
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) {
1653 if ((dyn
= pool_conf_alloc()) == NULL
)
1656 if (pool_conf_open(dyn
, pool_dynamic_location(),
1657 PO_RDONLY
) != PO_SUCCESS
) {
1658 pool_conf_free(dyn
);
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
);
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
);
1677 return (PO_SUCCESS
);
1681 * Free the resources for an XML data provider.
1684 pool_xml_connection_free(pool_xml_connection_t
*prov
)
1686 free((void *)prov
->pc_name
);
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
);
1705 (void) memset(rs
, 0, sizeof (pool_xml_result_set_t
));
1706 rs
->prs_conf
= conf
;
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
;
1722 * Free a result set. Ensure that the resources are all released at this point.
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
);
1735 * Transfer size from one resource to another.
1736 * Returns PO_SUCCESS/PO_FAIL
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
1751 pool_xml_res_xtransfer(pool_resource_t
*src
, pool_resource_t
*tgt
,
1752 pool_component_t
**rl
) {
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
])) ==
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
)
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)
1782 xset
->pxr_path
->nodesetval
->nodeTab
[++xset
->prs_index
]->_private
;
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
)
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)
1801 xset
->pxr_path
->nodesetval
->nodeTab
[xset
->prs_index
--]->_private
;
1806 * Sets the current index in a result set.
1807 * Returns PO_SUCCESS/PO_FAIL
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
);
1819 xset
->prs_index
= index
;
1820 return (PO_SUCCESS
);
1824 * Return the current index in a result set.
1825 * Returns current index
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
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
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
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
;
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
);
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
1934 pool_xml_resource_is_system(const pool_resource_t
*pr
)
1936 switch (pool_resource_elem_class(TO_ELEM(pr
))) {
1938 return (PSID_IS_SYSSET(
1939 elem_get_sysid(TO_ELEM(pr
))));
1946 * Note: This function is resource specific, needs extending for other
1950 pool_xml_resource_can_associate(const pool_resource_t
*pr
)
1952 switch (pool_resource_elem_class(TO_ELEM(pr
))) {
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
)
1972 if (pool_xml_put_property(TO_ELEM(pool
), "pool.res", &val
) !=
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
)
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
1999 * Returns PO_SUCCESS/PO_FAIL
2002 pool_xml_open_file(pool_conf_t
*conf
)
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.
2021 if (dtd_exists(dtd_location
) == PO_FALSE
) {
2022 pool_seterror(POE_DATASTORE
);
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
);
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
;
2043 if (fcntl(fileno(prov
->pxc_file
), F_SETLKW
, &lock
) == -1) {
2044 pool_seterror(POE_SYSTEM
);
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
);
2057 /* Parse the document */
2058 if (pool_xml_parse_document(conf
) != PO_SUCCESS
)
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
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
)
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
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
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
)
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
)
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
) {
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
) {
2123 pool_seterror(POE_BADPARAM
);
2127 if ((id
= xmlGetProp(pxe
->pxe_node
, BAD_CAST src_attr
))
2130 pool_seterror(POE_DATASTORE
);
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\"]",
2138 if ((classes
& PEC_QRY_SYSTEM
) != 0) {
2139 if (pool_build_xpath_buf(prov
, src
, PEC_SYSTEM
,
2140 props
, cb
, PO_TRUE
) == PO_FAIL
) {
2145 if ((classes
& PEC_QRY_POOL
) != 0) {
2146 if (pool_build_xpath_buf(prov
, src
, PEC_POOL
,
2147 props
, cb
, PO_TRUE
) == PO_FAIL
) {
2152 if ((classes
& PEC_QRY_RES_COMP
) != 0) {
2153 if (pool_build_xpath_buf(prov
, src
,
2154 PEC_RES_COMP
, props
, cb
, PO_TRUE
)
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
)
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
) {
2186 if ((classes
& PEC_QRY_POOL
) != 0) {
2187 if (pool_build_xpath_buf(prov
, src
, PEC_POOL
, props
,
2188 cb
, PO_FALSE
) == PO_FAIL
) {
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
) {
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
) {
2207 if ((classes
& PEC_QRY_COMP
) != 0) {
2208 if (pool_build_xpath_buf(prov
, src
, PEC_COMP
, props
,
2209 cb
, PO_FALSE
) == PO_FAIL
) {
2215 buf
= strdup(cb
->cb_buf
);
2218 * Have a buffer at this point, that we can use
2220 if ((rs
= pool_xml_result_set_alloc(conf
)) == NULL
) {
2225 * Set up the XPath Query
2227 if ((rs
->pxr_ctx
= xmlXPathNewContext(
2228 ((pool_xml_connection_t
*)conf
->pc_prov
)->pxc_doc
)) == NULL
) {
2230 (void) pool_xml_rs_close((pool_result_set_t
*)rs
);
2231 pool_seterror(POE_DATASTORE
);
2235 rs
->pxr_ctx
->node
= xmlDocGetRootElement
2236 (((pool_xml_connection_t
*)conf
->pc_prov
)->pxc_doc
);
2238 rs
->pxr_ctx
->node
= pxe
->pxe_node
;
2242 rs
->pxr_path
= xmlXPathEval(BAD_CAST buf
, rs
->pxr_ctx
);
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
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
)
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 */
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
, " |");
2287 (void) append_char_buf(cb
, " ./");
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
++) {
2303 const char *prop_name
;
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) {
2319 attr_name
= prop_name
;
2321 attr_name
= prop_name
+ strlen(prefix
) + 1;
2322 if (pool_is_xml_attr(prov
->pxc_doc
,
2323 element_class_tags
[class], attr_name
)) {
2325 prop_name
= attr_name
;
2326 if (class == PEC_RES_COMP
||
2327 class == PEC_RES_AGG
||
2328 class == PEC_COMP
) {
2330 type_prefix
= strdup(prefix
);
2340 * Add attributes/properties to the search buffer
2342 switch ((pvc
= pool_value_get_type(props
[i
]))) {
2344 (void) pool_value_get_uint64(props
[i
], &uval
);
2345 if (append_char_buf(cb
, fmts
[pvc
], prop_name
, uval
)
2352 (void) pool_value_get_int64(props
[i
], &ival
);
2353 if (append_char_buf(cb
, fmts
[pvc
], prop_name
, ival
)
2360 (void) pool_value_get_double(props
[i
], &dval
);
2361 if (append_char_buf(cb
, fmts
[pvc
], prop_name
, dval
)
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
) {
2376 (void) pool_value_get_string(props
[i
], &sval
);
2377 if (append_char_buf(cb
, fmts
[pvc
], prop_name
, sval
)
2385 pool_seterror(POE_INVALID_SEARCH
);
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
;
2401 if (suffix2
== NULL
)
2402 suffix2
= last_prop_name
;
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
) {
2413 while (*--where
!= '[')
2415 while (*--where
!= '[')
2422 last_prop_name
= prop_name
;
2424 if (has_type
== PO_FALSE
) {
2426 if (append_char_buf(cb
, ATTR_FMTS
[POC_STRING
],
2427 c_type
, type_prefix
) == PO_FAIL
) {
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.
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
;
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
)
2464 if (suffix2
== NULL
)
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.
2485 dtd_exists(const char *path
)
2489 if (strstr(path
, "file://") != path
)
2495 if (stat(&path
[7], &buf
) == 0)
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.
2507 build_dtype_accelerator(void)
2510 const xmlChar
*elem_list
[ELEM_TYPE_COUNT
] = {
2511 BAD_CAST
"res_comp",
2515 BAD_CAST
"property",
2516 BAD_CAST
"system" };
2519 if (_libpool_xml_initialised
== PO_TRUE
)
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
)
2544 for (i
= 0; i
< ELEM_TYPE_COUNT
; i
++) {
2546 xmlAttributePtr attr
;
2548 if ((elem
= xmlGetDtdElementDesc(dtd
, elem_list
[i
])) == NULL
)
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 */
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.
2575 (*build_dtype_tbl(const xmlChar
*rawdata
))[]
2579 dtype_tbl_t (*tbl
)[];
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
2589 if (rawdata
== NULL
)
2591 if ((data
= xmlStrdup(rawdata
)) == NULL
)
2593 if ((tbl
= calloc(max_attr
, sizeof (dtype_tbl_t
))) == NULL
) {
2597 for (tok
= strtok_r((char *)data
, " ", &lasts
); tok
!= NULL
;
2598 tok
= strtok_r(NULL
, " ", &lasts
)) {
2600 (*tbl
)[j
].dt_name
= xmlStrdup(BAD_CAST tok
);
2601 if ((tok
= strtok_r(NULL
, " ", &lasts
)) == NULL
) {
2603 for (j
= 0; j
< k
; j
++)
2604 free((*tbl
)[j
].dt_name
);
2605 pool_seterror(POE_DATASTORE
);
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
);
2623 (*tbl
)[j
].dt_name
= NULL
; /* Terminate the table */
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.
2634 get_fast_dtype(xmlNodePtr node
, xmlChar
*name
)
2639 if ((elem
= xmlGetDtdElementDesc(node
->doc
->extSubset
, node
->name
))
2641 pool_seterror(POE_BADPARAM
);
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
;
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
2668 * size must be >=4 in order for "content encoding detection" to work.
2671 pool_xml_parse_document(pool_conf_t
*conf
)
2674 char chars
[PAGE_READ_SIZE
];
2676 xmlParserCtxtPtr ctxt
;
2678 pool_xml_connection_t
*prov
= (pool_xml_connection_t
*)conf
->pc_prov
;
2680 pool_resource_t
**rsl
;
2684 if (fstat(fileno(prov
->pxc_file
), &f_stat
) == -1) {
2685 pool_seterror(POE_SYSTEM
);
2689 if (f_stat
.st_size
== 0) {
2690 pool_seterror(POE_INVALID_CONF
);
2693 size
= f_stat
.st_size
< 4 ? 4 : PAGE_READ_SIZE
;
2695 res
= fread(chars
, 1, size
, prov
->pxc_file
);
2698 xmlValidCtxtPtr cvp
;
2700 if ((ctxt
= xmlCreatePushParserCtxt(NULL
, NULL
,
2701 chars
, res
, conf
->pc_location
)) == NULL
) {
2702 pool_seterror(POE_INVALID_CONF
);
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
);
2713 if (xmlParseChunk(ctxt
, chars
, 0, 1) != 0) {
2714 xmlFreeParserCtxt(ctxt
);
2715 pool_seterror(POE_INVALID_CONF
);
2719 if ((cvp
= xmlNewValidCtxt()) == NULL
) {
2720 pool_seterror(POE_INVALID_CONF
);
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
);
2732 prov
->pxc_doc
= ctxt
->myDoc
;
2733 xmlFreeValidCtxt(cvp
);
2734 xmlFreeParserCtxt(ctxt
);
2736 if (prov
->pxc_doc
== NULL
) {
2737 pool_seterror(POE_INVALID_CONF
);
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
);
2748 * Ensure that the parsed tree has been contained within
2751 if (create_shadow(root
) != PO_SUCCESS
) {
2752 pool_seterror(POE_INVALID_CONF
);
2756 if (pool_xml_validate(conf
, POV_STRICT
) != PO_SUCCESS
) {
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
;
2770 if ((cs
= pool_query_resource_components(conf
,
2771 rsl
[i
], &size
, NULL
)) != NULL
) {
2773 pool_value_set_uint64(&val
, size
);
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
) {
2785 return (PO_SUCCESS
);