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