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