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