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