/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <thread.h>
#include <time.h>
#include <unistd.h>
#include <libxml/debugXML.h>
#include <libxml/xmlerror.h>
#include <libxml/xmlmemory.h>
#include <pool.h>
#include "pool_internal.h"
#include "pool_impl.h"
#include "pool_xml_impl.h"
/*
* libpool XML Manipulation Routines
*
* pool_xml.c implements the XML manipulation routines used by the libpool
* XML datastore. The functions are grouped into the following logical areas
* - Result Sets
* The XPath API is used to search the XML document represented by a
* configuration. The results of XPath queries are represented through
* pool_result_set_t structures as part of the abstraction of the datastore
* representation. (see pool.c comment for more details)
*
* - Property Manipulation
* Validated XML (XML associated with a DTD) does not allow the introduction
* of attributes which are not recognised by the DTD. This is a limitation
* since we want to allow libpool to associate an arbitrary number of
* properties with an element. The property manipulation code overcomes this
* limitation by allowing property sub-elements to be created and manipulated
* through a single API so that they are indistinguishable from attributes
* to the libpool user.
*
* These routines manipulate XML elements and attributes and are the routines
* which interact most directly with libxml.
*
* - File Processing/IO
* Since libpool must present its data in a consistent fashion, we have to
* implement file locking above libxml. These routines allow us to lock files
* during processing and maintain data integrity between processes. Note
* that locks are at the process scope and are advisory (see fcntl).
*
* - Utilities
* Sundry utility functions that aren't easily categorised.
*/
/*
* The PAGE_READ_SIZE value is used to determine the size of the input buffer
* used to parse XML files.
*/
typedef struct dtype_tbl
{
int dt_type;
} dtype_tbl_t;
typedef struct elem_type_tbl
{
extern int xmlDoValidityCheckingDefaultValue;
/*
* The _xml_lock is used to lock the state of libpool during
* xml initialisation operations.
*/
const char *element_class_tags[] = {
"any",
"system",
"pool",
"res_comp",
"res_agg",
"comp",
};
static const char *data_type_tags[] = {
"uint",
"int",
"float",
"boolean",
"string"
};
/* libpool initialisation indicator */
/*
* Utility functions
*/
/*
* Those functions which are not static are shared with pool_kernel.c
* They provide the required XML support for exporting a kernel
* configuration as an XML document.
*/
void xml_init(void);
static int prop_sort(const void *a, const void *b);
static int dtd_exists(const char *path);
static void build_dtype_accelerator(void);
static int pool_assoc_default_resource_type(pool_t *,
/*
* XML Data access and navigation APIs
*/
/*
* SHARED WITH pool_kernel.c for XML export support
*/
/* Configuration */
static int pool_xml_close(pool_conf_t *);
uint64_t);
pool_component_t **);
/* Connections */
/* Result Sets */
/* Element (and sub-type) */
/*
* Pool element specific
*/
/*
* Resource elements specific
*/
static int pool_xml_resource_is_system(const pool_resource_t *);
static int pool_xml_resource_can_associate(const pool_resource_t *);
/* Properties */
const char *, pool_value_t *);
static int pool_xml_put_property(pool_elem_t *, const char *,
const pool_value_t *);
static int pool_xml_rm_property(pool_elem_t *, const char *);
static int pool_is_xml_attr(xmlDocPtr, const char *, const char *);
const pool_value_t *value);
const pool_value_t *value);
/* XML Error handling */
/* XML File Input Processing */
static int pool_xml_parse_document(pool_conf_t *);
/*
* Initialise this module
*/
void
xml_init()
{
(void) mutex_lock(&_xml_lock);
if (_libpool_xml_initialised == PO_TRUE) {
(void) mutex_unlock(&_xml_lock);
return;
}
/*
* DTD validation, with line numbers.
*/
(void) xmlLineNumbersDefault(1);
/* Try to improve indentation and readability */
(void) xmlKeepBlanksDefault(0);
/* Send all XML errors to our debug handler */
/* Load up DTD element a-dtype data to improve performance */
(void) mutex_unlock(&_xml_lock);
}
/*
* Get the next ID for this configuration
*/
static int
{
if (pool_get_ns_property(
}
return (PO_FAIL);
}
return (pool_put_ns_property(
&val));
}
/* Document building functions */
/*
* node_create() creates a child node of type name of the supplied parent in
* the supplied document. If the parent or document is NULL, create the node
* but do not associate it with a parent or document.
*/
{
else
return (node);
}
/*
* node_create_with_id() creates a child node of type name of the supplied
* parent with the ref_id generated by get_unique_id(). Actual node creation
* is performed by node_create() and this function just sets the ref_id
* property to the value of the id.
*/
static xmlNodePtr
{
return (NULL);
}
return (NULL);
}
}
return (node);
}
/* Supporting Data Conversion Routines */
/* XML Parser Utility Functions */
/*
* Handler for XML Errors. Called by libxml at libxml Error.
*/
/*ARGSUSED*/
void
{
}
/*
* Free the shadowed elements from within the supplied document and then
* free the document. This function should always be called when freeing
* a pool document to ensure that all "shadow" resources are reclaimed.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/* Only do any of this if there is a document */
/* Delete all the "shadowed" children of the doc */
return (PO_FAIL);
}
/*
* Work out the element type and free the elem
*/
}
(void) pool_rs_close(rs);
}
return (PO_SUCCESS);
}
/*
* Remove an element from the document. Note that only three types of elements
* can be removed, res, comp and pools. comp are moved around to the
* default res when a res is deleted.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/*
* You can only destroy three elements: pools, resources and
* components.
*/
case PEC_POOL:
case PEC_RES_COMP:
case PEC_RES_AGG:
case PEC_COMP:
}
break;
default:
break;
}
return (PO_SUCCESS);
}
/*
* Create a property element.
*/
static xmlNodePtr
{
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (element);
}
/*
* way to do it.
* This function is an interceptor, since it will *always* try to manipulate
* an attribute first. If the attribute doesn't exist, then it will treat
* the request as a property request.
*/
static pool_value_class_t
{
/*
* "type" is a special attribute which is not visible ever outside of
* libpool. Use the specific type accessor function.
*/
val));
}
== POC_INVAL)
val));
} else
return (type);
}
/*
* Put a property on an element. Check if the property is an attribute,
* if it is update that value. If not add a property element.
*
* There are three possible conditions here:
* - the name is a ns
* - the name is an attribute
* - the name isn't an attribute
* - the name is not a ns
* Returns PO_SUCCESS/PO_FAIL
*/
static int
const pool_value_t *val)
{
/*
* "type" is a special attribute which is not visible ever outside of
* libpool. Use the specific type accessor function.
*/
val));
}
val));
} else
return (PO_SUCCESS);
}
/*
* Remove a property from an element. Check if the property is an attribute,
* if it is fail. Otherwise remove the property subelement.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
int ret;
return (PO_FAIL);
}
/* use xpath to find the node with the appropriate value for name */
return (PO_FAIL);
}
ret = PO_SUCCESS;
} else {
}
return (ret);
}
/*
* Get the data type for an attribute name from the element node. The data
* type is returned and the value of the attribute updates the supplied value
* pointer.
*/
static pool_value_class_t
{
return (POC_INVAL);
}
return (POC_INVAL);
}
return (POC_INVAL);
}
switch (data_type) {
case POC_UINT:
errno = 0;
if (errno != 0) {
}
else
break;
case POC_INT:
errno = 0;
if (errno != 0) {
}
else
break;
case POC_DOUBLE:
break;
case POC_BOOL:
else
break;
case POC_STRING:
return (POC_INVAL);
}
break;
case POC_INVAL:
default:
break;
}
return (data_type);
}
/*
* Set the data type for an attribute name from the element node. The
* supplied value is used to update the designated name using the data
* type supplied.
*/
int
{
double dres;
const char *sres;
return (PO_FAIL);
}
return (PO_FAIL);
}
return (PO_FAIL);
}
case POC_UINT:
(u_longlong_t)ures);
break;
case POC_INT:
(longlong_t)ires);
break;
case POC_DOUBLE:
break;
case POC_BOOL:
"false");
else
"true");
break;
case POC_STRING:
sres);
break;
case POC_INVAL:
default:
break;
}
return (PO_FAIL);
}
return (PO_SUCCESS);
}
/*
* Get the data type for a property name from the element node. The data
* type is returned and the value of the property updates the supplied value
* pointer. The user is responsible for freeing the memory associated with
* a string.
*/
static pool_value_class_t
{
/* use xpath to find the node with the appropriate value for name */
return (POC_INVAL);
}
int i;
return (POC_INVAL);
}
/* type is a string representation of the type */
for (i = 0; i < (sizeof (data_type_tags) /
sizeof (data_type_tags[0])); i++) {
data_type = i;
break;
}
}
switch (data_type) {
case POC_UINT:
errno = 0;
if (errno != 0)
else
break;
case POC_INT:
errno = 0;
if (errno != 0)
else
break;
case POC_DOUBLE:
break;
case POC_BOOL:
== 0)
else
break;
case POC_STRING:
(const char *)node_data) != PO_SUCCESS) {
break;
}
break;
case POC_INVAL:
default:
break;
}
return (data_type);
} else { /* No property exists, clean up and return */
return (POC_INVAL);
}
}
/*
* Set the data type for a property name from the element node. The
* supplied value is used to update the designated name using the data
* type supplied.
*/
int
{
/* First check if we have a property with this name (and type???). */
double dres;
const char *sres;
/* use xpath to find the node with the appropriate value for name */
name);
return (PO_FAIL);
}
return (PO_FAIL);
} else {
int i;
return (PO_FAIL);
}
for (i = 0; i < (sizeof (data_type_tags) /
sizeof (data_type_tags[0])); i++)
== 0) {
break;
}
return (PO_FAIL);
}
} else {
return (PO_FAIL);
}
}
case POC_UINT:
(u_longlong_t)ures);
break;
case POC_INT:
(longlong_t)ires);
break;
case POC_DOUBLE:
break;
case POC_BOOL:
"false");
else
"true");
break;
case POC_STRING:
break;
case POC_INVAL:
default:
break;
}
return (PO_SUCCESS);
}
/*
* Return a NULL terminated array of pool_value_t which represents all
* of the properties stored for an element
*
* Return NULL on failure. It is the caller's responsibility to free
* the returned array of values.
*/
pool_value_t **
{
int i, j;
*nprops = 0;
(*nprops)++;
}
if ((ctx = xmlXPathNewContext(
return (NULL);
}
return (NULL);
}
return (NULL);
}
/*
* Now store our attributes and properties in result
*/
i--;
continue;
}
result[i] = pool_value_alloc();
while (i-- >= 0)
pool_value_free(result[i]);
return (NULL);
}
PO_SUCCESS) {
while (i-- >= 0)
pool_value_free(result[i]);
return (NULL);
}
PO_SUCCESS) {
while (i-- >= 0)
pool_value_free(result[i]);
return (NULL);
}
} else {
if (pool_value_set_name(result[i],
while (i-- >= 0)
pool_value_free(result[i]);
return (NULL);
}
}
}
result[i] = pool_value_alloc();
POC_INVAL) {
while (i-- >= 0)
pool_value_free(result[i]);
return (NULL);
}
PO_SUCCESS) {
while (i-- >= 0)
pool_value_free(result[i]);
return (NULL);
}
}
return (result);
}
/*
* Store a pointer to one of our data types in the _private member of each
* XML data node contained within the passed node. Note this function is
* recursive and so all sub-nodes are also shadowed. Only shadow the nodes
* which we are interested in, i.e. system, pool, res and comp
*/
static int
{
/* Create a data structure of the appropriate type */
(char *)data);
}
/* Have to shadow all children and all siblings */
break;
}
return (ret);
}
/*
* XML Data access and navigation APIs
*/
/*
* Close the configuration. There are a few steps to closing a configuration:
* - Unlock the backing file (if there is one)
* - Close the file (if there is one)
* - Free the shadow memory }Done in pool_xml_free_doc
* - Free the document }
* - Free the data provider for this configuration
* - Free the configuration location specifier
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/* Close (and implicitly) unlock the file */
}
}
/* Close the xml specific parts */
(void) pool_xml_free_doc(conf);
return (ret);
}
/*
* Remove the configuration from the backing store. In XML terms delete
* the file backing the configuration. You need a copy of the location
* since the pool_conf_close function, frees the location.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/* First unlink the file, to prevent races on open */
return (PO_FAIL);
}
/* Now close the configuration */
(void) pool_conf_close(conf);
return (PO_SUCCESS);
}
return (PO_FAIL);
}
/*
* Validate the configuration. There are three levels of validation, loose,
* strict and runtime. In this, XML, implementation, loose is mapped to XML
* validation, strict implements additional application level validation
* checks, e.g. all pools must have unique names, runtime ensures that this
* configuration would instantiate on the current system.
*
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
return (PO_FAIL);
}
return (PO_FAIL);
}
if (level >= POV_RUNTIME) {
/*
* Note: This is resource specific.
*/
PO_SUCCESS) &&
}
return (PO_SUCCESS);
}
/*
* Commit the configuration to the backing store. In XML terms this means
* write the changes to the backing file. Read the comments below for details
* on exactly how this operation is performed.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/*
* Ensure that the configuration file has no contents
*/
return (PO_FAIL);
}
return (PO_FAIL);
}
/*
* Create an XML output buffer and write out the contents of the
* configuration to the file.
*/
return (PO_FAIL);
}
return (PO_FAIL);
}
return (PO_SUCCESS);
}
/*
* Export the configuration in the specified format to the specified location.
* The only format implemented now is the native format, which saves the
* active configuration to the supplied location.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
int ret;
switch (fmt) {
case POX_NATIVE:
1);
if (ret == -1) {
return (PO_FAIL);
} else
return (PO_SUCCESS);
default:
return (PO_FAIL);
}
}
/*
* Discard the configuration and restore the configuration to the values
* specified in the configuration location.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/* Rollback the file pointer ready for the reparse */
return (PO_FAIL);
}
/* Reparse the document */
/* In XML terms this means, discard and reparse the document */
(void) pool_xml_free_doc(conf);
return (PO_FAIL);
return (PO_SUCCESS);
}
/*
* Allocate a new pool_elem_t in the supplied configuration of the specified
* class.
*/
static void
{
/* Set up the function pointers for element manipulation */
/*
* Specific initialisation for different types of element
*/
}
}
}
/*
* "Wrap" a suplied XML node with a pool_elem_t sub-type of the supplied
* class.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/* Need to do some messing about to support SubTypes */
switch (class) {
case PEC_SYSTEM:
return (PO_FAIL);
}
break;
case PEC_POOL:
return (PO_FAIL);
}
break;
case PEC_RES_COMP:
case PEC_RES_AGG:
return (PO_FAIL);
}
break;
case PEC_COMP:
return (PO_FAIL);
}
break;
}
return (PO_SUCCESS);
}
/*
* Associate a pool to the default resource for the supplied resource
* type.
*/
int
{
PO_SUCCESS ||
return (PO_FAIL);
}
return (PO_FAIL);
}
PO_SUCCESS) {
return (PO_FAIL);
}
return (PO_FAIL);
}
return (PO_FAIL);
}
/*
* One default resource set per type
*/
if (rl_size != 1) {
return (PO_FAIL);
}
return (PO_FAIL);
}
return (PO_SUCCESS);
}
/*
* Create an XML node in the supplied configuration with a pool_elem_t
* sub-type of the supplied class.
*/
static pool_elem_t *
{
/* In XML terms, create an element of the appropriate class */
if (class == PEC_INVALID) {
return (NULL);
}
/* Now create the XML component and add to it's parent */
/*
* If we know the class of an element, we know it's parent.
* PEC_POOL, the parent must be the system node
* PEC_RES, treat as pool.
* PEC_COMP, we don't know the parent, leave this up to the
* create_comp function.
*/
/* Since we know the subtype we can create and populate the sub-type */
switch (class) {
case PEC_POOL:
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (NULL);
}
break;
case PEC_RES_COMP:
case PEC_RES_AGG:
return (NULL);
}
return (NULL);
}
return (NULL);
}
return (NULL);
}
break;
case PEC_COMP:
return (NULL);
}
return (NULL);
}
break;
default:
return (NULL);
}
/*
* Put the type and an invalid sys_id on the node.
*/
return (NULL);
}
return (NULL);
}
}
/*
* Note: This is resource specific.
*/
return (NULL);
}
}
return ((pool_elem_t *)elem);
}
/*
* Allocate a data provider for the supplied configuration and optionally
* discover resources.
* The data provider is the cross over point from the "abstract" configuration
* functions into the data representation specific manipulation routines.
* This function sets up all the required pointers to create an XML aware
* data provider.
* Returns PO_SUCCESS/PO_FAIL
*/
int
{
xml_init();
return (PO_FAIL);
}
/*
* Initialise data members
*/
/*
* Initialise function pointers
*/
/*
* End of common initialisation
*/
/*
* Associate the provider to it's configuration
*/
/*
* At this point the configuration provider has been initialized,
* mark the configuration as valid so that the various routines
* which rely on a valid configuration will work correctly.
*/
return (PO_FAIL);
PO_RDONLY) != PO_SUCCESS) {
return (PO_FAIL);
}
POX_NATIVE) != PO_SUCCESS) {
(void) pool_conf_close(dyn);
return (PO_FAIL);
}
(void) pool_conf_close(dyn);
}
(void) pool_xml_close(conf);
return (PO_FAIL);
}
return (PO_SUCCESS);
}
/*
* Free the resources for an XML data provider.
*/
static void
{
}
/*
* Allocate a result set. The Result Set stores the result of an XPath
* query along with the parameters used to create the result set (for
* debugging purposes).
*/
static pool_xml_result_set_t *
{
return (NULL);
}
/* Fix up the result set accessor functions to the xml specfic ones */
return (rs);
}
/*
* Free a result set. Ensure that the resources are all released at this point.
*/
static void
{
}
/*
* Transfer size from one resource to another.
* Returns PO_SUCCESS/PO_FAIL
*/
/* ARGSUSED */
int
{
return (PO_SUCCESS);
}
/*
* Transfer components rl from one resource to another.
* Returns PO_SUCCESS/PO_FAIL
*/
/* ARGSUSED */
int
pool_component_t **rl) {
int i;
/*
* Walk the Result Set and move the resource components
*/
PO_FAIL) {
return (PO_FAIL);
}
}
return (PO_SUCCESS);
}
/*
* Return the next element in a result set.
*/
static pool_elem_t *
{
/* Since I know this is an XML result set */
/* Update the context node */
return (NULL);
next =
return (next);
}
/*
* Return the previous element in a result set.
*/
static pool_elem_t *
{
/* Since I know this is an XML result set */
/* Update the context node */
return (NULL);
prev =
return (prev);
}
/*
* Sets the current index in a result set.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/* Since I know this is an XML result set */
return (PO_FAIL);
}
return (PO_SUCCESS);
}
/*
* Return the current index in a result set.
* Returns current index
*/
static int
{
/* Since I know this is an XML result set */
}
/*
* Return the first element in a result set.
*/
static pool_elem_t *
{
/* Since I know this is an XML result set */
/* Update the context node */
}
/*
* Return the last element in a result set.
*/
static pool_elem_t *
{
/* Since I know this is an XML result set */
/* Update the context node */
}
/*
* Return the number of results in a result set.
* Returns result count
*/
static int
{
}
/*
* Close a result set. Remove this result set from the list of results and
* free the resources
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
return (PO_SUCCESS);
}
/*
* Set the container for a node.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
/* Try to move back */
return (PO_FAIL);
}
return (PO_SUCCESS);
}
/*
* Get the container for a node.
*/
static pool_elem_t *
{
}
/*
* Note: This function is resource specific, needs extending for other
* resource types.
*/
int
{
case PREC_PSET:
return (PSID_IS_SYSSET(
default:
return (PO_FALSE);
}
}
/*
* Note: This function is resource specific, needs extending for other
* resource types.
*/
int
{
case PREC_PSET:
return (PO_TRUE);
default:
return (PO_FALSE);
}
}
/*
* Note: This function is resource specific. It must be extended to support
* multiple resource types.
*/
int
{
return (PO_FAIL);
return (PO_FAIL);
return (PO_SUCCESS);
}
/*
* pool_xml_pool_dissociate() simply finds the default resource for
* the type of resource being dissociated and then calls
* pool_xml_pool_associate() to associate to the default resource.
*/
int
{
return (PO_FAIL);
if (default_res == pr)
return (PO_SUCCESS);
}
/*
* pool_xml_open_file() opens a file for a configuration. This establishes
* the locks required to ensure data integrity when manipulating a
* configuration.
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
struct stat s;
/*
* Always close the pxc_file in case there was a previously failed open
*/
}
/*
* Check that the DTD required for this operation is present.
* If it isn't fail
*/
return (PO_FAIL);
}
else /* Assume opening PO_RDONLY */
return (PO_FAIL);
}
/*
* Setup the lock for the file
*/
return (PO_FAIL);
}
/*
* Check to see if the document was removed whilst waiting for
* the lock. If it was return an error.
*/
return (PO_FAIL);
}
/* Parse the document */
return (PO_FAIL);
return (PO_SUCCESS);
}
/*
* Try to work out if an element contains an attribute of the supplied name.
* Search the internal subset first and then the external subset.
* Return PO_TRUE if there is an attribute of that name declared for that
* element.
*/
int
{
return (PO_FALSE);
return (PO_TRUE);
}
/*
* Execute the specified query using XPath. This complex function relies on
* a couple of helpers to build up an XPath query, pool_build_xpath_buf in
* particular.
* conf - the pool configuration being manipulated
* src - the root of the search, if NULL that means whole document
* src_attr - if supplied means an IDREF(S) search on this attribute
* classes - target classes
* props - target properties
*/
{
return (NULL);
/*
* Prior to building up the complex XPath query, check to see if
* src_attr is an IDREF(S). If it is use the IDREF(S) information
* to generate the query rather than the other data
*/
char *tok;
char *lasts;
/*
* Check the arguments for consistency
*/
return (NULL);
}
== NULL) {
return (NULL);
}
or = " | ";
if ((classes & PEC_QRY_SYSTEM) != 0) {
return (NULL);
}
}
if ((classes & PEC_QRY_POOL) != 0) {
return (NULL);
}
}
if ((classes & PEC_QRY_RES_COMP) != 0) {
== PO_FAIL) {
return (NULL);
}
} else if ((classes & PEC_QRY_RES_AGG) != 0) {
== PO_FAIL) {
return (NULL);
}
}
}
} else {
/*
* Build up an XPath query using the supplied parameters.
* The basic logic is to:
* - Identify which classes are the targets of the query
* - For each class work out if the props are attributes or not
* - Build up a piece of XPath for each class
* - Combine the results into one large XPath query.
* - Execute the query.
*/
if ((classes & PEC_QRY_SYSTEM) != 0) {
return (NULL);
}
}
if ((classes & PEC_QRY_POOL) != 0) {
return (NULL);
}
}
if ((classes & PEC_QRY_RES_COMP) != 0) {
return (NULL);
}
}
if ((classes & PEC_QRY_RES_AGG) != 0) {
return (NULL);
}
}
if ((classes & PEC_QRY_COMP) != 0) {
return (NULL);
}
}
}
/*
* Have a buffer at this point, that we can use
*/
return (NULL);
}
/*
* Set up the XPath Query
*/
return (NULL);
}
else
/*
* Select
*/
/*
* Generate the result set and wrap the results as pool_elem_t
*/
return ((pool_result_set_t *)rs);
}
/*
* Build an XPath query buffer. This is complex and a little fragile, but
* I'm trying to accomplish something complex with as little code as possible.
* I wait the implementation of XMLQuery with baited breath...
* Returns PO_SUCCESS/PO_FAIL
*/
static int
{
int i;
const char *ATTR_FMTS[] = {
"[ @%s=\"%llu\" ]", /* POC_UINT */
"[ @%s=\"%lld\" ]", /* POC_INT */
"[ @%s=\"%f\" ]", /* POC_DOUBLE */
"[ @%s=\"%s\" ]", /* POC_BOOL */
"[ @%s=\"%s\" ]", /* POC_STRING */
};
const char *PROP_FMTS[] = {
"[ property[@name=\"%s\"][text()=\"%llu\"] ]", /* POC_UINT */
"[ property[@name=\"%s\"][text()=\"%lld\"] ]", /* POC_INT */
"[ property[@name=\"%s\"][text()=\"%f\"] ]", /* POC_DOUBLE */
"[ property[@name=\"%s\"][text()=\"%s\"] ]", /* POC_BOOL */
"[ property[@name=\"%s\"][text()=\"%s\"] ]" /* POC_STRING */
};
const char **fmts;
int nprop;
else
}
return (PO_SUCCESS);
/* Count properties */;
/*
* Sort the attributes and properties by name.
*/
for (i = 0; i < nprop; i++) {
int is_attr = 0;
const char *prefix;
const char *prop_name;
double dval;
const char *sval;
const char *attr_name;
/*
* Possibly an attribute. Strip off the prefix.
*/
} else
is_attr = 1;
if (class == PEC_RES_COMP ||
class == PEC_RES_AGG ||
if (type_prefix != NULL)
}
}
}
if (is_attr) {
} else {
}
/*
* Add attributes/properties to the search buffer
*/
case POC_UINT:
== PO_FAIL) {
return (PO_FAIL);
}
break;
case POC_INT:
== PO_FAIL) {
return (PO_FAIL);
}
break;
case POC_DOUBLE:
== PO_FAIL) {
return (PO_FAIL);
}
break;
case POC_BOOL:
return (PO_FAIL);
}
break;
case POC_STRING:
== PO_FAIL) {
return (PO_FAIL);
}
break;
default:
return (PO_FAIL);
}
if (last_prop_name != NULL) {
/*
* Extra fiddling for namespaces
*/
else
suffix1++;
else
suffix2++;
} else {
}
/* repeat */
while (*--where != '[')
;
while (*--where != '[')
;
}
*where = 'r';
}
}
}
if (type_prefix) {
return (PO_FAIL);
}
}
}
return (PO_SUCCESS);
}
/*
* Utility routine for use by quicksort. Assumes that the supplied data
* are pool values and compares the names of the two pool values.
* Returns an integer greater than, equal to, or less than 0.
*/
static int
prop_sort(const void *a, const void *b)
{
const char *str_a;
const char *str_b;
/*
* Extra fiddling for namespaces
*/
else
suffix1++;
else
suffix2++;
} else {
}
}
/*
* Order the elements by (ref_id)
*/
/*
* system. It is assumed that the supplied path is in URL format and represents
* a file and so file:// is stripped from the start of the search.
*/
static int
{
return (PO_FALSE);
if (path[7] == 0)
return (PO_FALSE);
return (PO_TRUE);
return (PO_FALSE);
}
/*
* Build the dtype structures to accelerate data type lookup operations. The
* purpose is to avoid expensive XML manipulations on data which will not
* change over the life of a library invocation. It is designed to be invoked
* once from the library init function.
*/
static void
build_dtype_accelerator(void)
{
BAD_CAST "res_comp",
BAD_CAST "res_agg",
BAD_CAST "comp",
BAD_CAST "pool",
BAD_CAST "property",
BAD_CAST "system" };
int i;
if (_libpool_xml_initialised == PO_TRUE)
return;
/* Load up the d-type data for each element */
/*
* Store data type information in nested lists
* Top level list contains attribute declaration pointers which
* can be used to match with supplied nodes.
* Second level list contains attribute type information for each
* element declaration
*/
/*
* Unfortunately, there's no easy way to get a list of all DTD
* element descriptions as there is no libxml API to do this (they
* are stored in a hash, which I guess is why). Explicitly seek
* for descriptions for elements that are known to hold an a-dtype
* attribute and build accelerators for those elements.
* If the DTD changes, the library may have to change as well now,
* since this code makes explicit assumptions about which elements
* contain a-dtype information.
*/
return;
for (i = 0; i < ELEM_TYPE_COUNT; i++) {
return;
/* Walk the list of attributes looking for a-dtype */
/*
* Allocate a dtype_tbl_t
*/
/* This could have returned NULL */
}
}
}
}
/*
* build_dtype_tbl() parses the supplied data and returns an array (max size
* of 10, increase if required) of dtype_tbl_t structures holding data type
* information for an element. The supplied data is assumed to be in "a-dtype"
* format. The dtype_tbl_t array is NULL terminated, which is why space for
* 11 members is allocated.
*/
static dtype_tbl_t
{
char *tok;
char *lasts;
dtype_tbl_t (*tbl)[];
int j = 0;
/*
* Parse the supplied data, assumed to be in a-dtype format, and
* generate a lookup table which is indexed by the name and contains
* the data type
*/
return (NULL);
return (NULL);
return (NULL);
}
int i;
int k = j;
for (j = 0; j < k; j++)
return (NULL);
}
for (i = 0; i < (sizeof (data_type_tags) /
sizeof (data_type_tags[0])); i++) {
}
if (j == max_attr) { /* too many attributes, bail out */
for (j = 0; j < max_attr; j++)
return (NULL);
}
}
return (tbl);
}
/*
* get_fast_dtype() finds the data type for a supplied attribute name on a
* supplied node. This is called get_fast_dtype() because it uses the cached
* data type information created at library initialisation.
*/
static int
{
int i;
== NULL) {
return (POC_INVAL);
}
for (i = 0; i < ELEM_TYPE_COUNT; i++) {
int j = 0;
break;
break; /* if we didn't find it in the elem, break */
}
}
/* If we can't find it, say it's a string */
return (POC_STRING);
}
/*
* pool_xml_parse_document() parses the file associated with a supplied
* configuration to regenerate the runtime representation. The supplied
* configuration must reference an already opened file and this is used
* to generate the XML representation via the configuration provider's
* pxc_doc member.
* size must be >=4 in order for "content encoding detection" to work.
*/
static int
{
int res;
int i;
return (PO_FAIL);
}
return (PO_FAIL);
} else
if (res >= 4) {
return (PO_FAIL);
}
return (PO_FAIL);
}
}
return (PO_FAIL);
}
return (PO_FAIL);
}
return (PO_FAIL);
}
}
return (PO_FAIL);
}
/* Get the root element */
return (PO_FAIL);
}
/*
* Ensure that the parsed tree has been contained within
* our shadow tree.
*/
return (PO_FAIL);
}
return (PO_FAIL);
}
/*
* For backwards compatibility with S9, make sure that all
* resources have a size and that it is correct.
*/
for (i = 0; i < nelem; i++) {
} else
pool_value_set_uint64(&val, 0);
return (PO_FAIL);
}
}
}
}
return (PO_SUCCESS);
}