#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 <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <libxml/debugXML.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlerror.h>
#include <libxml/xpath.h>
#include <libxml/xmlmemory.h>
#include <pool.h>
#include "pool_internal.h"
#include "pool_impl.h"
#include "pool_xml_impl.h"
#define MAX_PROP_SIZE 1024
#define PAGE_READ_SIZE 8192
#define ELEM_TYPE_COUNT 6
typedef struct dtype_tbl
{
xmlChar *dt_name;
int dt_type;
} dtype_tbl_t;
typedef struct elem_type_tbl
{
xmlChar *ett_elem;
dtype_tbl_t (*ett_dtype)[];
} elem_type_tbl_t;
extern int xmlDoValidityCheckingDefaultValue;
static mutex_t _xml_lock;
const char *element_class_tags[] = {
"any",
"system",
"pool",
"res_comp",
"res_agg",
"comp",
NULL
};
static const char *data_type_tags[] = {
"uint",
"int",
"float",
"boolean",
"string"
};
const char *dtd_location = "file:///usr/share/lib/xml/dtd/rm_pool.dtd.1";
static elem_type_tbl_t elem_tbl[ELEM_TYPE_COUNT] = {0};
static int _libpool_xml_initialised = PO_FALSE;
void xml_init(void);
static int create_shadow(xmlNodePtr node);
static int pool_xml_free_doc(pool_conf_t *conf);
static int prop_sort(const void *a, const void *b);
static int dtd_exists(const char *path);
static void build_dtype_accelerator(void);
static dtype_tbl_t (*build_dtype_tbl(const xmlChar *rawdata))[];
static int get_fast_dtype(xmlNodePtr node, xmlChar *name);
static int pool_assoc_default_resource_type(pool_t *,
pool_resource_elem_class_t);
static int pool_build_xpath_buf(pool_xml_connection_t *, const pool_elem_t *,
pool_elem_class_t, pool_value_t **, char_buf_t *, int);
xmlNodePtr node_create(xmlNodePtr parent, const xmlChar *name);
static xmlNodePtr node_create_with_id(xmlNodePtr parent, const xmlChar *name);
static int pool_xml_close(pool_conf_t *);
static int pool_xml_validate(const pool_conf_t *, pool_valid_level_t);
static int pool_xml_commit(pool_conf_t *conf);
static int pool_xml_export(const pool_conf_t *conf, const char *location,
pool_export_format_t fmt);
static int pool_xml_rollback(pool_conf_t *conf);
static 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);
static int pool_xml_remove(pool_conf_t *conf);
static int pool_xml_res_transfer(pool_resource_t *, pool_resource_t *,
uint64_t);
static int pool_xml_res_xtransfer(pool_resource_t *, pool_resource_t *,
pool_component_t **);
static void pool_xml_connection_free(pool_xml_connection_t *prov);
static pool_xml_result_set_t *pool_xml_result_set_alloc(const pool_conf_t *);
static void pool_xml_result_set_free(pool_xml_result_set_t *rs);
static pool_elem_t *pool_xml_rs_next(pool_result_set_t *set);
static pool_elem_t *pool_xml_rs_prev(pool_result_set_t *set);
static pool_elem_t *pool_xml_rs_first(pool_result_set_t *set);
static pool_elem_t *pool_xml_rs_last(pool_result_set_t *set);
static int pool_xml_rs_set_index(pool_result_set_t *set, int index);
static int pool_xml_rs_get_index(pool_result_set_t *set);
static int pool_xml_rs_count(pool_result_set_t *set);
static int pool_xml_rs_close(pool_result_set_t *set);
static void pool_xml_elem_init(pool_conf_t *conf, pool_xml_elem_t *elem,
pool_elem_class_t, pool_resource_elem_class_t, pool_component_elem_class_t);
static int pool_xml_elem_wrap(xmlNodePtr node, pool_elem_class_t class,
pool_resource_elem_class_t, pool_component_elem_class_t);
static pool_elem_t *pool_xml_elem_create(pool_conf_t *, pool_elem_class_t,
pool_resource_elem_class_t, pool_component_elem_class_t);
static int pool_xml_elem_remove(pool_elem_t *pe);
static int pool_xml_set_container(pool_elem_t *, pool_elem_t *);
static pool_elem_t *pool_xml_get_container(const pool_elem_t *);
static int pool_xml_pool_associate(pool_t *, const pool_resource_t *);
static int pool_xml_pool_dissociate(pool_t *, const pool_resource_t *);
static int pool_xml_resource_is_system(const pool_resource_t *);
static int pool_xml_resource_can_associate(const pool_resource_t *);
static pool_value_class_t pool_xml_get_property(const pool_elem_t *,
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 xmlNodePtr property_create(xmlNodePtr, const char *,
pool_value_class_t);
static int pool_is_xml_attr(xmlDocPtr, const char *, const char *);
static pool_value_class_t pool_xml_get_attr(xmlNodePtr node, xmlChar *name,
pool_value_t *value);
int pool_xml_set_attr(xmlNodePtr node, xmlChar *name,
const pool_value_t *value);
static pool_value_class_t pool_xml_get_prop(xmlNodePtr node, xmlChar *name,
pool_value_t *value);
int pool_xml_set_prop(xmlNodePtr node, xmlChar *name,
const pool_value_t *value);
static pool_value_t **pool_xml_get_properties(const pool_elem_t *, uint_t *);
void pool_error_func(void *ctx, const char *msg, ...);
static int pool_xml_open_file(pool_conf_t *conf);
static int pool_xml_parse_document(pool_conf_t *);
void
xml_init()
{
(void) mutex_lock(&_xml_lock);
if (_libpool_xml_initialised == PO_TRUE) {
(void) mutex_unlock(&_xml_lock);
return;
}
xmlInitParser();
xmlSetGenericErrorFunc(NULL, pool_error_func);
build_dtype_accelerator();
_libpool_xml_initialised = PO_TRUE;
(void) mutex_unlock(&_xml_lock);
}
static int
get_unique_id(xmlNodePtr node, char *id)
{
pool_value_t val = POOL_VALUE_INITIALIZER;
uint64_t nid = 0;
if (node->doc->_private) {
if (pool_get_ns_property(
pool_conf_to_elem((pool_conf_t *)node->doc->_private),
"_next_id", &val) == POC_UINT)
(void) pool_value_get_uint64(&val, &nid);
}
if (snprintf(id, KEY_BUFFER_SIZE, "id_%llx", nid) > KEY_BUFFER_SIZE) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
pool_value_set_uint64(&val, ++nid);
return (pool_put_ns_property(
pool_conf_to_elem((pool_conf_t *)node->doc->_private), "_next_id",
&val));
}
xmlNodePtr
node_create(xmlNodePtr parent, const xmlChar *name)
{
xmlNodePtr node;
if (parent == NULL)
node = xmlNewNode(NULL, name);
else
node = xmlNewChild(parent, NULL, name, NULL);
return (node);
}
static xmlNodePtr
node_create_with_id(xmlNodePtr parent, const xmlChar *name)
{
char id[KEY_BUFFER_SIZE];
xmlNodePtr node = node_create(parent, name);
if (node != NULL) {
if (get_unique_id(node, id) != PO_SUCCESS) {
xmlUnlinkNode(node);
xmlFreeNode(node);
pool_seterror(POE_DATASTORE);
return (NULL);
}
if (xmlSetProp(node, BAD_CAST c_ref_id, BAD_CAST id) == NULL) {
xmlUnlinkNode(node);
xmlFreeNode(node);
pool_seterror(POE_DATASTORE);
return (NULL);
}
}
return (node);
}
void
pool_error_func(void *ctx, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
do_dprintf(msg, ap);
va_end(ap);
}
static int
pool_xml_free_doc(pool_conf_t *conf)
{
if (((pool_xml_connection_t *)conf->pc_prov)->pxc_doc != NULL) {
pool_elem_t *pe;
pool_result_set_t *rs;
rs = pool_exec_query(conf, NULL, NULL, PEC_QRY_ANY, NULL);
if (rs == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
for (pe = rs->prs_next(rs); pe != NULL; pe = rs->prs_next(rs)) {
free(pe);
}
(void) pool_rs_close(rs);
xmlFreeDoc(((pool_xml_connection_t *)conf->pc_prov)->pxc_doc);
}
((pool_xml_connection_t *)conf->pc_prov)->pxc_doc = NULL;
return (PO_SUCCESS);
}
static int
pool_xml_elem_remove(pool_elem_t *pe)
{
pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe;
switch (pe->pe_class) {
case PEC_POOL:
case PEC_RES_COMP:
case PEC_RES_AGG:
case PEC_COMP:
if (pxe->pxe_node) {
xmlUnlinkNode(pxe->pxe_node);
xmlFreeNode(pxe->pxe_node);
}
free(pxe);
break;
default:
break;
}
return (PO_SUCCESS);
}
static xmlNodePtr
property_create(xmlNodePtr parent, const char *name, pool_value_class_t type)
{
xmlNodePtr element;
pool_value_t val = POOL_VALUE_INITIALIZER;
if ((element = node_create(parent, BAD_CAST "property")) == NULL) {
pool_seterror(POE_DATASTORE);
return (NULL);
}
if (pool_value_set_string(&val, name) != PO_SUCCESS) {
xmlFree(element);
return (NULL);
}
(void) pool_xml_set_attr(element, BAD_CAST c_name, &val);
if (pool_value_set_string(&val, data_type_tags[type]) != PO_SUCCESS) {
xmlFree(element);
return (NULL);
}
(void) pool_xml_set_attr(element, BAD_CAST c_type, &val);
return (element);
}
static pool_value_class_t
pool_xml_get_property(const pool_elem_t *pe, const char *name,
pool_value_t *val)
{
pool_value_class_t type;
pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe;
if (strcmp(name, c_type) == 0) {
return (pool_xml_get_attr(pxe->pxe_node, BAD_CAST name,
val));
}
if (is_ns_property(pe, name) != NULL) {
if ((type = pool_xml_get_attr(pxe->pxe_node,
BAD_CAST property_name_minus_ns(pe, name), val))
== POC_INVAL)
return (pool_xml_get_prop(pxe->pxe_node, BAD_CAST name,
val));
} else
return (pool_xml_get_prop(pxe->pxe_node, BAD_CAST name, val));
return (type);
}
static int
pool_xml_put_property(pool_elem_t *pe, const char *name,
const pool_value_t *val)
{
pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe;
if (strcmp(name, c_type) == 0) {
return (pool_xml_set_attr(pxe->pxe_node, BAD_CAST name,
val));
}
if (is_ns_property(pe, name) != NULL) {
if (pool_xml_set_attr(pxe->pxe_node,
BAD_CAST property_name_minus_ns(pe, name), val) == PO_FAIL)
return (pool_xml_set_prop(pxe->pxe_node, BAD_CAST name,
val));
} else
return (pool_xml_set_prop(pxe->pxe_node, BAD_CAST name, val));
return (PO_SUCCESS);
}
static int
pool_xml_rm_property(pool_elem_t *pe, const char *name)
{
pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe;
xmlXPathContextPtr ctx;
xmlXPathObjectPtr path;
char buf[MAX_PROP_SIZE];
int ret;
if (xmlHasProp(pxe->pxe_node, BAD_CAST name) != NULL) {
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
(void) snprintf(buf, sizeof (buf), "property[@name=\"%s\"]", name);
if ((ctx = xmlXPathNewContext(pxe->pxe_node->doc)) == NULL) {
pool_seterror(POE_PUTPROP);
return (PO_FAIL);
}
ctx->node = pxe->pxe_node;
path = xmlXPathEval(BAD_CAST buf, ctx);
if (path && (path->type == XPATH_NODESET) &&
(path->nodesetval->nodeNr == 1)) {
xmlUnlinkNode(path->nodesetval->nodeTab[0]);
xmlFreeNode(path->nodesetval->nodeTab[0]);
ret = PO_SUCCESS;
} else {
pool_seterror(POE_BADPARAM);
ret = PO_FAIL;
}
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
return (ret);
}
static pool_value_class_t
pool_xml_get_attr(xmlNodePtr node, xmlChar *name, pool_value_t *value)
{
pool_value_class_t data_type;
xmlChar *data;
uint64_t uval;
int64_t ival;
if (xmlHasProp(node, name) == NULL && pool_is_xml_attr(node->doc,
(const char *) node->name, (const char *) name) == PO_FALSE) {
pool_seterror(POE_BADPARAM);
return (POC_INVAL);
}
if (xmlHasProp(node, BAD_CAST c_a_dtype) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (POC_INVAL);
}
data = xmlGetProp(node, name);
data_type = get_fast_dtype(node, name);
if (data_type != POC_STRING && data == NULL) {
pool_seterror(POE_INVALID_CONF);
return (POC_INVAL);
}
switch (data_type) {
case POC_UINT:
errno = 0;
uval = strtoull((char *)data, NULL, 0);
if (errno != 0) {
data_type = POC_INVAL;
}
else
pool_value_set_uint64(value, uval);
break;
case POC_INT:
errno = 0;
ival = strtoll((char *)data, NULL, 0);
if (errno != 0) {
data_type = POC_INVAL;
}
else
pool_value_set_int64(value, ival);
break;
case POC_DOUBLE:
pool_value_set_double(value, atof((const char *)data));
break;
case POC_BOOL:
if (strcmp((const char *)data, "true") == 0)
pool_value_set_bool(value, PO_TRUE);
else
pool_value_set_bool(value, PO_FALSE);
break;
case POC_STRING:
if (pool_value_set_string(value, data ?
(const char *)data : "") != PO_SUCCESS) {
xmlFree(data);
return (POC_INVAL);
}
break;
case POC_INVAL:
default:
break;
}
xmlFree(data);
return (data_type);
}
int
pool_xml_set_attr(xmlNodePtr node, xmlChar *name, const pool_value_t *value)
{
xmlChar buf[MAX_PROP_SIZE] = {0};
uint64_t ures;
int64_t ires;
uchar_t bres;
double dres;
const char *sres;
pool_value_class_t data_type;
if (xmlHasProp(node, name) == NULL && pool_is_xml_attr(node->doc,
(const char *) node->name, (const char *) name) == PO_FALSE) {
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
if (xmlHasProp(node, BAD_CAST c_a_dtype) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
data_type = get_fast_dtype(node, name);
if (data_type != value->pv_class) {
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
switch (value->pv_class) {
case POC_UINT:
(void) pool_value_get_uint64(value, &ures);
(void) snprintf((char *)buf, sizeof (buf), "%llu",
(u_longlong_t)ures);
break;
case POC_INT:
(void) pool_value_get_int64(value, &ires);
(void) snprintf((char *)buf, sizeof (buf), "%lld",
(longlong_t)ires);
break;
case POC_DOUBLE:
(void) pool_value_get_double(value, &dres);
(void) snprintf((char *)buf, sizeof (buf), "%f", dres);
break;
case POC_BOOL:
(void) pool_value_get_bool(value, &bres);
if (bres == PO_FALSE)
(void) snprintf((char *)buf, sizeof (buf),
"false");
else
(void) snprintf((char *)buf, sizeof (buf),
"true");
break;
case POC_STRING:
(void) pool_value_get_string(value, &sres);
if (sres != NULL)
(void) snprintf((char *)buf, sizeof (buf), "%s",
sres);
break;
case POC_INVAL:
default:
break;
}
if (xmlSetProp(node, name, buf) == NULL) {
pool_seterror(POE_DATASTORE);
return (PO_FAIL);
}
return (PO_SUCCESS);
}
static pool_value_class_t
pool_xml_get_prop(xmlNodePtr node, xmlChar *name, pool_value_t *value)
{
pool_value_class_t data_type;
xmlChar *data, *node_data;
xmlXPathContextPtr ctx;
xmlXPathObjectPtr path;
char buf[MAX_PROP_SIZE];
int64_t uval;
int64_t ival;
(void) snprintf(buf, sizeof (buf), "property[@name=\"%s\"]", name);
if ((ctx = xmlXPathNewContext(node->doc)) == NULL) {
pool_seterror(POE_BADPARAM);
return (POC_INVAL);
}
ctx->node = node;
path = xmlXPathEval(BAD_CAST buf, ctx);
if (path && (path->type == XPATH_NODESET) &&
(path->nodesetval->nodeNr == 1)) {
int i;
if (xmlHasProp(path->nodesetval->nodeTab[0],
BAD_CAST c_type) == NULL) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
pool_seterror(POE_INVALID_CONF);
return (POC_INVAL);
}
data = xmlGetProp(path->nodesetval->nodeTab[0],
BAD_CAST c_type);
node_data = xmlNodeGetContent(path->nodesetval->nodeTab[0]);
data_type = POC_INVAL;
for (i = 0; i < (sizeof (data_type_tags) /
sizeof (data_type_tags[0])); i++) {
if (strcmp((char *)data, data_type_tags[i]) == 0) {
data_type = i;
break;
}
}
switch (data_type) {
case POC_UINT:
errno = 0;
uval = strtoull((char *)node_data, NULL, 0);
if (errno != 0)
data_type = POC_INVAL;
else
pool_value_set_uint64(value, uval);
break;
case POC_INT:
errno = 0;
ival = strtoll((char *)node_data, NULL, 0);
if (errno != 0)
data_type = POC_INVAL;
else
pool_value_set_int64(value, ival);
break;
case POC_DOUBLE:
pool_value_set_double(value,
atof((const char *)node_data));
break;
case POC_BOOL:
if (strcmp((const char *)node_data, "true")
== 0)
pool_value_set_bool(value, PO_TRUE);
else
pool_value_set_bool(value, PO_FALSE);
break;
case POC_STRING:
if (pool_value_set_string(value,
(const char *)node_data) != PO_SUCCESS) {
data_type = POC_INVAL;
break;
}
break;
case POC_INVAL:
default:
break;
}
xmlFree(data);
xmlFree(node_data);
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
return (data_type);
} else {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
pool_seterror(POE_BADPARAM);
return (POC_INVAL);
}
}
int
pool_xml_set_prop(xmlNodePtr node, xmlChar *name, const pool_value_t *value)
{
xmlXPathContextPtr ctx;
xmlXPathObjectPtr path;
xmlChar buf[MAX_PROP_SIZE];
xmlNodePtr element;
uint64_t ures;
int64_t ires;
uchar_t bres;
double dres;
const char *sres;
(void) snprintf((char *)buf, sizeof (buf), "property[@name=\"%s\"]",
name);
if ((ctx = xmlXPathNewContext(node->doc)) == NULL) {
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
ctx->node = node;
path = xmlXPathEval(buf, ctx);
if (path == NULL || path->type != XPATH_NODESET) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
} else {
if (path->nodesetval->nodeNr == 0)
element = property_create
(node, (const char *)name, value->pv_class);
else if (path->nodesetval->nodeNr == 1) {
int i;
xmlChar *data;
element = path->nodesetval->nodeTab[0];
if (xmlHasProp(element, BAD_CAST c_type) == NULL) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
data = xmlGetProp(element, BAD_CAST c_type);
for (i = 0; i < (sizeof (data_type_tags) /
sizeof (data_type_tags[0])); i++)
if (strcmp((char *)data, data_type_tags[i])
== 0) {
break;
}
xmlFree(data);
if (value->pv_class != i) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
} else {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
}
switch (value->pv_class) {
case POC_UINT:
(void) pool_value_get_uint64(value, &ures);
(void) snprintf((char *)buf, sizeof (buf), "%llu",
(u_longlong_t)ures);
break;
case POC_INT:
(void) pool_value_get_int64(value, &ires);
(void) snprintf((char *)buf, sizeof (buf), "%lld",
(longlong_t)ires);
break;
case POC_DOUBLE:
(void) pool_value_get_double(value, &dres);
(void) snprintf((char *)buf, sizeof (buf), "%f", dres);
break;
case POC_BOOL:
(void) pool_value_get_bool(value, &bres);
if (bres == PO_FALSE)
(void) snprintf((char *)buf, sizeof (buf),
"false");
else
(void) snprintf((char *)buf, sizeof (buf),
"true");
break;
case POC_STRING:
(void) pool_value_get_string(value, &sres);
(void) snprintf((char *)buf, sizeof (buf), "%s", sres);
break;
case POC_INVAL:
default:
break;
}
xmlNodeSetContent(element, buf);
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
return (PO_SUCCESS);
}
pool_value_t **
pool_xml_get_properties(const pool_elem_t *pe, uint_t *nprops)
{
pool_value_t **result;
pool_xml_elem_t *pxe = (pool_xml_elem_t *)pe;
int i, j;
pool_conf_t *conf = TO_CONF(pe);
xmlElementPtr elemDTD;
xmlAttributePtr attr;
xmlXPathContextPtr ctx;
xmlXPathObjectPtr path;
char_buf_t *cb = NULL;
*nprops = 0;
elemDTD = xmlGetDtdElementDesc(pxe->pxe_node->doc->extSubset,
pxe->pxe_node->name);
for (attr = elemDTD->attributes; attr != NULL; attr = attr->nexth) {
if (strcmp((const char *)attr->name, c_a_dtype) != 0 ||
strcmp((const char *)attr->name, c_type) != 0)
(*nprops)++;
}
if ((ctx = xmlXPathNewContext(
((pool_xml_connection_t *)conf->pc_prov)->pxc_doc)) == NULL) {
pool_seterror(POE_BADPARAM);
return (NULL);
}
ctx->node = pxe->pxe_node;
path = xmlXPathEval(BAD_CAST "property", ctx);
if (path != NULL && path->type == XPATH_NODESET &&
path->nodesetval != NULL)
(*nprops) += path->nodesetval->nodeNr;
if ((result = calloc(*nprops + 1, sizeof (pool_value_t *))) == NULL) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
pool_seterror(POE_SYSTEM);
return (NULL);
}
if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
free(result);
return (NULL);
}
for (i = 0, attr = elemDTD->attributes; attr != NULL;
attr = attr->nexth, i++) {
if (strcmp((const char *)attr->name, c_a_dtype) == 0 ||
strcmp((const char *)attr->name, c_type) == 0) {
i--;
continue;
}
result[i] = pool_value_alloc();
if (pool_xml_get_attr(pxe->pxe_node,
BAD_CAST attr->name, result[i]) == POC_INVAL) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
while (i-- >= 0)
pool_value_free(result[i]);
free(result);
free_char_buf(cb);
return (NULL);
}
if (strcmp((const char *)attr->name, c_type) != 0) {
if (set_char_buf(cb, "%s.%s",
pool_elem_class_string(pe), attr->name) !=
PO_SUCCESS) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
while (i-- >= 0)
pool_value_free(result[i]);
free(result);
free_char_buf(cb);
return (NULL);
}
if (pool_value_set_name(result[i], cb->cb_buf) !=
PO_SUCCESS) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
while (i-- >= 0)
pool_value_free(result[i]);
free(result);
free_char_buf(cb);
return (NULL);
}
} else {
if (pool_value_set_name(result[i],
(const char *)attr->name) != PO_SUCCESS) {
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
while (i-- >= 0)
pool_value_free(result[i]);
free(result);
free_char_buf(cb);
return (NULL);
}
}
}
free_char_buf(cb);
for (j = 0; j < path->nodesetval->nodeNr; j++, i++) {
xmlChar *name = xmlGetProp(path->nodesetval->nodeTab[j],
BAD_CAST c_name);
result[i] = pool_value_alloc();
if (pool_xml_get_prop(pxe->pxe_node, name, result[i]) ==
POC_INVAL) {
xmlFree(name);
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
while (i-- >= 0)
pool_value_free(result[i]);
free(result);
return (NULL);
}
if (pool_value_set_name(result[i], (const char *)name) !=
PO_SUCCESS) {
xmlFree(name);
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
while (i-- >= 0)
pool_value_free(result[i]);
free(result);
return (NULL);
}
xmlFree(name);
}
xmlXPathFreeObject(path);
xmlXPathFreeContext(ctx);
return (result);
}
static int
create_shadow(xmlNodePtr node)
{
xmlNodePtr sib;
int ret = PO_SUCCESS;
if (0 == (xmlStrcmp(node->name,
BAD_CAST element_class_tags[PEC_SYSTEM]))) {
ret = pool_xml_elem_wrap(node, PEC_SYSTEM, PREC_INVALID,
PCEC_INVALID);
} else if (0 == (xmlStrcmp(node->name,
BAD_CAST element_class_tags[PEC_POOL]))) {
ret = pool_xml_elem_wrap(node, PEC_POOL, PREC_INVALID,
PCEC_INVALID);
} else if (0 == (xmlStrcmp(node->name,
BAD_CAST element_class_tags[PEC_RES_COMP]))) {
xmlChar *data;
pool_resource_elem_class_t res_class;
data = xmlGetProp(node, BAD_CAST c_type);
res_class = pool_resource_elem_class_from_string((char *)data);
xmlFree(data);
ret = pool_xml_elem_wrap(node, PEC_RES_COMP, res_class,
PCEC_INVALID);
} else if (0 == (xmlStrcmp(node->name,
BAD_CAST element_class_tags[PEC_RES_AGG]))) {
xmlChar *data;
pool_resource_elem_class_t res_class;
data = xmlGetProp(node, BAD_CAST c_type);
res_class = pool_resource_elem_class_from_string((char *)data);
xmlFree(data);
ret = pool_xml_elem_wrap(node, PEC_RES_AGG, res_class,
PCEC_INVALID);
} else if (0 == (xmlStrcmp(node->name,
BAD_CAST element_class_tags[PEC_COMP]))) {
xmlChar *data;
pool_component_elem_class_t comp_class;
data = xmlGetProp(node, BAD_CAST c_type);
comp_class = pool_component_elem_class_from_string(
(char *)data);
xmlFree(data);
ret = pool_xml_elem_wrap(node, PEC_COMP, PREC_INVALID,
comp_class);
}
for (sib = node->children; sib != NULL; sib = sib->next) {
if ((ret = create_shadow(sib)) != PO_SUCCESS)
break;
}
return (ret);
}
static int
pool_xml_close(pool_conf_t *conf)
{
pool_xml_connection_t *pxc = (pool_xml_connection_t *)conf->pc_prov;
int ret = PO_SUCCESS;
if (pxc->pxc_file != NULL) {
if (fclose(pxc->pxc_file) != 0) {
pool_seterror(POE_SYSTEM);
ret = PO_FAIL;
}
pxc->pxc_file = NULL;
}
(void) pool_xml_free_doc(conf);
pool_xml_connection_free((pool_xml_connection_t *)conf->pc_prov);
return (ret);
}
static int
pool_xml_remove(pool_conf_t *conf)
{
if (pool_conf_location(conf) != NULL) {
if (unlink(pool_conf_location(conf)) != 0) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
(void) pool_conf_close(conf);
return (PO_SUCCESS);
}
return (PO_FAIL);
}
static int
pool_xml_validate(const pool_conf_t *conf, pool_valid_level_t level)
{
pool_xml_connection_t *pxc = (pool_xml_connection_t *)conf->pc_prov;
xmlValidCtxtPtr cvp;
if ((cvp = xmlNewValidCtxt()) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
cvp->error = pool_error_func;
cvp->warning = pool_error_func;
if (xmlValidateDocument(cvp, pxc->pxc_doc) == 0) {
xmlFreeValidCtxt(cvp);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
xmlFreeValidCtxt(cvp);
if (level >= POV_RUNTIME) {
return (((pool_validate_resource(conf, "pset", c_min_prop, 0) ==
PO_SUCCESS) &&
(pool_validate_resource(conf, "pset", c_max_prop, 0) ==
PO_SUCCESS)) ? PO_SUCCESS : PO_FAIL);
}
return (PO_SUCCESS);
}
static int
pool_xml_commit(pool_conf_t *conf)
{
pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov;
xmlOutputBufferPtr buf;
if (fseek(prov->pxc_file, 0, SEEK_SET) != 0) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
if (ftruncate(fileno(prov->pxc_file), 0) == -1) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
if ((buf = xmlOutputBufferCreateFile(prov->pxc_file, NULL)) == NULL) {
pool_seterror(POE_DATASTORE);
return (PO_FAIL);
}
if (xmlSaveFormatFileTo(buf, prov->pxc_doc, NULL, 1) == -1) {
pool_seterror(POE_DATASTORE);
return (PO_FAIL);
}
return (PO_SUCCESS);
}
static int
pool_xml_export(const pool_conf_t *conf, const char *location,
pool_export_format_t fmt)
{
int ret;
switch (fmt) {
case POX_NATIVE:
ret = xmlSaveFormatFile(location,
((pool_xml_connection_t *)conf->pc_prov)->pxc_doc,
1);
if (ret == -1) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
} else
return (PO_SUCCESS);
default:
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
}
static int
pool_xml_rollback(pool_conf_t *conf)
{
pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov;
if (fseek(prov->pxc_file, 0, SEEK_SET) != 0) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
(void) pool_xml_free_doc(conf);
if (pool_xml_parse_document(conf) == PO_FAIL)
return (PO_FAIL);
return (PO_SUCCESS);
}
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)
{
pool_elem_t *pe = TO_ELEM(elem);
pe->pe_conf = conf;
pe->pe_class = class;
pe->pe_resource_class = res_class;
pe->pe_component_class = comp_class;
pe->pe_get_prop = pool_xml_get_property;
pe->pe_put_prop = pool_xml_put_property;
pe->pe_rm_prop = pool_xml_rm_property;
pe->pe_get_props = pool_xml_get_properties;
pe->pe_remove = pool_xml_elem_remove;
pe->pe_get_container = pool_xml_get_container;
pe->pe_set_container = pool_xml_set_container;
if (class == PEC_POOL) {
pool_xml_pool_t *pp = (pool_xml_pool_t *)elem;
pp->pp_associate = pool_xml_pool_associate;
pp->pp_dissociate = pool_xml_pool_dissociate;
}
if (class == PEC_RES_COMP || class == PEC_RES_AGG) {
pool_xml_resource_t *pr = (pool_xml_resource_t *)elem;
pr->pr_is_system = pool_xml_resource_is_system;
pr->pr_can_associate = pool_xml_resource_can_associate;
}
}
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)
{
pool_conf_t *conf = node->doc->_private;
pool_xml_elem_t *elem;
switch (class) {
case PEC_SYSTEM:
if ((elem = malloc(sizeof (pool_xml_system_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
(void) memset(elem, 0, sizeof (pool_xml_system_t));
break;
case PEC_POOL:
if ((elem = malloc(sizeof (pool_xml_pool_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
(void) memset(elem, 0, sizeof (pool_xml_pool_t));
break;
case PEC_RES_COMP:
case PEC_RES_AGG:
if ((elem = malloc(sizeof (pool_xml_resource_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
(void) memset(elem, 0, sizeof (pool_xml_resource_t));
break;
case PEC_COMP:
if ((elem = malloc(sizeof (pool_xml_component_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
(void) memset(elem, 0, sizeof (pool_xml_component_t));
break;
}
pool_xml_elem_init(conf, elem, class, res_class, comp_class);
node->_private = elem;
elem->pxe_node = node;
return (PO_SUCCESS);
}
int
pool_assoc_default_resource_type(pool_t *pool, pool_resource_elem_class_t type)
{
pool_value_t *props[] = { NULL, NULL, NULL };
uint_t rl_size;
pool_resource_t **rsl;
pool_conf_t *conf = TO_ELEM(pool)->pe_conf;
char_buf_t *cb = NULL;
pool_value_t val0 = POOL_VALUE_INITIALIZER;
pool_value_t val1 = POOL_VALUE_INITIALIZER;
props[0] = &val0;
props[1] = &val1;
if (pool_value_set_string(props[0], pool_resource_type_string(type)) !=
PO_SUCCESS ||
pool_value_set_name(props[0], c_type) != PO_SUCCESS) {
return (PO_FAIL);
}
if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL) {
return (PO_FAIL);
}
if (set_char_buf(cb, "%s.default",
pool_resource_type_string(type)) !=
PO_SUCCESS) {
free_char_buf(cb);
return (PO_FAIL);
}
if (pool_value_set_name(props[1], cb->cb_buf) != PO_SUCCESS) {
free_char_buf(cb);
return (PO_FAIL);
}
pool_value_set_bool(props[1], PO_TRUE);
free_char_buf(cb);
if ((rsl = pool_query_resources(conf, &rl_size, props)) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
if (rl_size != 1) {
free(rsl);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
if (pool_associate(conf, pool, rsl[0]) < 0) {
free(rsl);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
free(rsl);
return (PO_SUCCESS);
}
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)
{
pool_xml_elem_t *elem;
pool_elem_t *parent;
pool_system_t *parent_system;
if (class == PEC_INVALID) {
pool_seterror(POE_BADPARAM);
return (NULL);
}
switch (class) {
case PEC_POOL:
if ((parent_system = pool_conf_system(conf)) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (NULL);
}
if ((parent = pool_system_elem(parent_system)) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (NULL);
}
if ((elem = malloc(sizeof (pool_xml_system_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (NULL);
}
(void) memset(elem, 0, sizeof (pool_xml_system_t));
if ((elem->pxe_node = node_create_with_id(
((pool_xml_elem_t *)parent)->pxe_node,
BAD_CAST element_class_tags[class])) == NULL) {
pool_seterror(POE_DATASTORE);
(void) pool_xml_elem_remove((pool_elem_t *)elem);
return (NULL);
}
break;
case PEC_RES_COMP:
case PEC_RES_AGG:
if ((parent_system = pool_conf_system(conf)) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (NULL);
}
if ((parent = pool_system_elem(parent_system)) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (NULL);
}
if ((elem = malloc(sizeof (pool_xml_resource_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (NULL);
}
(void) memset(elem, 0, sizeof (pool_xml_resource_t));
if ((elem->pxe_node = node_create_with_id
(((pool_xml_elem_t *)parent)->pxe_node,
BAD_CAST element_class_tags[class])) == NULL) {
pool_seterror(POE_DATASTORE);
(void) pool_xml_elem_remove((pool_elem_t *)elem);
return (NULL);
}
break;
case PEC_COMP:
if ((elem = malloc(sizeof (pool_xml_component_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (NULL);
}
(void) memset(elem, 0, sizeof (pool_xml_component_t));
if ((elem->pxe_node = node_create(NULL,
BAD_CAST element_class_tags[class])) == NULL) {
pool_seterror(POE_DATASTORE);
(void) pool_xml_elem_remove((pool_elem_t *)elem);
return (NULL);
}
break;
default:
pool_seterror(POE_BADPARAM);
return (NULL);
}
pool_xml_elem_init(conf, elem, class, res_class, comp_class);
elem->pxe_node->_private = elem;
if (class == PEC_RES_COMP || class == PEC_RES_AGG ||
class == PEC_COMP) {
if (xmlSetProp(elem->pxe_node, BAD_CAST c_sys_prop,
BAD_CAST POOL_SYSID_BAD_STRING) == NULL) {
pool_seterror(POE_DATASTORE);
(void) pool_xml_elem_remove((pool_elem_t *)elem);
return (NULL);
}
if (xmlSetProp(elem->pxe_node, BAD_CAST c_type,
BAD_CAST pool_elem_class_string(
(pool_elem_t *)elem)) == NULL) {
pool_seterror(POE_DATASTORE);
(void) pool_xml_elem_remove((pool_elem_t *)elem);
return (NULL);
}
}
if (class == PEC_POOL) {
if (pool_assoc_default_resource_type(pool_elem_pool(
(pool_elem_t *)elem), PREC_PSET) == PO_FAIL) {
(void) pool_xml_elem_remove((pool_elem_t *)elem);
return (NULL);
}
}
return ((pool_elem_t *)elem);
}
int
pool_xml_connection_alloc(pool_conf_t *conf, int oflags)
{
pool_xml_connection_t *prov;
xml_init();
if ((prov = malloc(sizeof (pool_xml_connection_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
(void) memset(prov, 0, sizeof (pool_xml_connection_t));
prov->pc_name = strdup("LIBXML 2.4.0");
prov->pc_store_type = XML_DATA_STORE;
prov->pc_oflags = oflags;
prov->pc_close = pool_xml_close;
prov->pc_validate = pool_xml_validate;
prov->pc_commit = pool_xml_commit;
prov->pc_export = pool_xml_export;
prov->pc_rollback = pool_xml_rollback;
prov->pc_exec_query = pool_xml_exec_query;
prov->pc_elem_create = pool_xml_elem_create;
prov->pc_remove = pool_xml_remove;
prov->pc_res_xfer = pool_xml_res_transfer;
prov->pc_res_xxfer = pool_xml_res_xtransfer;
conf->pc_prov = (pool_connection_t *)prov;
conf->pc_state = POF_VALID;
if ((oflags & PO_CREAT) != 0) {
pool_conf_t *dyn;
if ((dyn = pool_conf_alloc()) == NULL)
return (PO_FAIL);
if (pool_conf_open(dyn, pool_dynamic_location(),
PO_RDONLY) != PO_SUCCESS) {
pool_conf_free(dyn);
return (PO_FAIL);
}
if (pool_conf_export(dyn, conf->pc_location,
POX_NATIVE) != PO_SUCCESS) {
(void) pool_conf_close(dyn);
pool_conf_free(dyn);
return (PO_FAIL);
}
(void) pool_conf_close(dyn);
pool_conf_free(dyn);
}
if (pool_xml_open_file(conf) == PO_FAIL) {
(void) pool_xml_close(conf);
return (PO_FAIL);
}
return (PO_SUCCESS);
}
static void
pool_xml_connection_free(pool_xml_connection_t *prov)
{
free((void *)prov->pc_name);
free(prov);
}
static pool_xml_result_set_t *
pool_xml_result_set_alloc(const pool_conf_t *conf)
{
pool_xml_result_set_t *rs;
if ((rs = malloc(sizeof (pool_xml_result_set_t))) == NULL) {
pool_seterror(POE_SYSTEM);
return (NULL);
}
(void) memset(rs, 0, sizeof (pool_xml_result_set_t));
rs->prs_conf = conf;
rs->prs_index = -1;
rs->prs_active = PO_TRUE;
rs->prs_next = pool_xml_rs_next;
rs->prs_prev = pool_xml_rs_prev;
rs->prs_first = pool_xml_rs_first;
rs->prs_last = pool_xml_rs_last;
rs->prs_get_index = pool_xml_rs_get_index;
rs->prs_set_index = pool_xml_rs_set_index;
rs->prs_close = pool_xml_rs_close;
rs->prs_count = pool_xml_rs_count;
return (rs);
}
static void
pool_xml_result_set_free(pool_xml_result_set_t *rs)
{
if (rs->pxr_path != NULL)
xmlXPathFreeObject(rs->pxr_path);
if (rs->pxr_ctx != NULL)
xmlXPathFreeContext(rs->pxr_ctx);
free(rs);
}
int
pool_xml_res_transfer(pool_resource_t *src, pool_resource_t *tgt, uint64_t size)
{
return (PO_SUCCESS);
}
int
pool_xml_res_xtransfer(pool_resource_t *src, pool_resource_t *tgt,
pool_component_t **rl) {
int i;
for (i = 0; rl[i] != NULL; i++) {
if (pool_set_container(TO_ELEM(tgt), TO_ELEM(rl[i])) ==
PO_FAIL) {
return (PO_FAIL);
}
}
return (PO_SUCCESS);
}
static pool_elem_t *
pool_xml_rs_next(pool_result_set_t *set)
{
pool_elem_t *next;
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
if (xset->prs_index == xset->pxr_path->nodesetval->nodeNr - 1)
return (NULL);
next =
xset->pxr_path->nodesetval->nodeTab[++xset->prs_index]->_private;
return (next);
}
static pool_elem_t *
pool_xml_rs_prev(pool_result_set_t *set)
{
pool_elem_t *prev;
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
if (xset->prs_index < 0)
return (NULL);
prev =
xset->pxr_path->nodesetval->nodeTab[xset->prs_index--]->_private;
return (prev);
}
static int
pool_xml_rs_set_index(pool_result_set_t *set, int index)
{
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
if (index < 0 || index >= xset->pxr_path->nodesetval->nodeNr) {
pool_seterror(POE_BADPARAM);
return (PO_FAIL);
}
xset->prs_index = index;
return (PO_SUCCESS);
}
static int
pool_xml_rs_get_index(pool_result_set_t *set)
{
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
return (xset->prs_index);
}
static pool_elem_t *
pool_xml_rs_first(pool_result_set_t *set)
{
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
return (xset->pxr_path->nodesetval->nodeTab[0]->_private);
}
static pool_elem_t *
pool_xml_rs_last(pool_result_set_t *set)
{
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
return (xset->pxr_path->nodesetval->
nodeTab[xset->pxr_path->nodesetval->nodeNr-1]->_private);
}
static int
pool_xml_rs_count(pool_result_set_t *set)
{
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
return (xset->pxr_path->nodesetval->nodeNr);
}
static int
pool_xml_rs_close(pool_result_set_t *set)
{
pool_xml_result_set_t *xset = (pool_xml_result_set_t *)set;
pool_xml_result_set_free(xset);
return (PO_SUCCESS);
}
static int
pool_xml_set_container(pool_elem_t *pp, pool_elem_t *pc)
{
pool_xml_elem_t *pxp;
pool_xml_elem_t *pxc;
xmlNodePtr parent;
pxp = (pool_xml_elem_t *)pp;
pxc = (pool_xml_elem_t *)pc;
parent = pxc->pxe_node->parent;
xmlUnlinkNode(pxc->pxe_node);
if (xmlAddChild(pxp->pxe_node, pxc->pxe_node) == NULL) {
(void) xmlAddChild(parent, pxc->pxe_node);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
pc->pe_conf = pp->pe_conf;
return (PO_SUCCESS);
}
static pool_elem_t *
pool_xml_get_container(const pool_elem_t *pc)
{
pool_xml_elem_t *pxc = (pool_xml_elem_t *)pc;
return ((pool_elem_t *)pxc->pxe_node->parent->_private);
}
int
pool_xml_resource_is_system(const pool_resource_t *pr)
{
switch (pool_resource_elem_class(TO_ELEM(pr))) {
case PREC_PSET:
return (PSID_IS_SYSSET(
elem_get_sysid(TO_ELEM(pr))));
default:
return (PO_FALSE);
}
}
int
pool_xml_resource_can_associate(const pool_resource_t *pr)
{
switch (pool_resource_elem_class(TO_ELEM(pr))) {
case PREC_PSET:
return (PO_TRUE);
default:
return (PO_FALSE);
}
}
int
pool_xml_pool_associate(pool_t *pool, const pool_resource_t *pr)
{
pool_value_t val = POOL_VALUE_INITIALIZER;
if (pool_xml_get_property(TO_ELEM(pr),
"pset.ref_id", &val) != POC_STRING)
return (PO_FAIL);
if (pool_xml_put_property(TO_ELEM(pool), "pool.res", &val) !=
PO_SUCCESS)
return (PO_FAIL);
return (PO_SUCCESS);
}
int
pool_xml_pool_dissociate(pool_t *pool, const pool_resource_t *pr)
{
const pool_resource_t *default_res;
if ((default_res = get_default_resource(pr)) == NULL)
return (PO_FAIL);
if (default_res == pr)
return (PO_SUCCESS);
return (pool_xml_pool_associate(pool, default_res));
}
static int
pool_xml_open_file(pool_conf_t *conf)
{
struct flock lock;
struct stat s;
pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov;
if (prov->pxc_file != NULL) {
(void) fclose(prov->pxc_file);
prov->pxc_file = NULL;
}
if (dtd_exists(dtd_location) == PO_FALSE) {
pool_seterror(POE_DATASTORE);
return (PO_FAIL);
}
if ((prov->pc_oflags & PO_RDWR) != 0)
prov->pxc_file = fopen(conf->pc_location, "r+F");
else
prov->pxc_file = fopen(conf->pc_location, "rF");
if (prov->pxc_file == NULL) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
lock.l_type = (prov->pc_oflags & PO_RDWR) ? F_WRLCK : F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
if (fcntl(fileno(prov->pxc_file), F_SETLKW, &lock) == -1) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
if (stat(conf->pc_location, &s) == -1) {
(void) fclose(prov->pxc_file);
prov->pxc_file = NULL;
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
if (pool_xml_parse_document(conf) != PO_SUCCESS)
return (PO_FAIL);
return (PO_SUCCESS);
}
int
pool_is_xml_attr(xmlDocPtr doc, const char *elem, const char *attr)
{
xmlDtdPtr internal = xmlGetIntSubset(doc);
xmlDtdPtr external = doc->extSubset;
if (xmlGetDtdAttrDesc(internal, BAD_CAST elem, BAD_CAST attr) == NULL)
if (xmlGetDtdAttrDesc(external,
BAD_CAST elem, BAD_CAST attr) == NULL)
return (PO_FALSE);
return (PO_TRUE);
}
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)
{
char *buf = NULL;
char_buf_t *cb = NULL;
pool_xml_result_set_t *rs;
pool_xml_elem_t *pxe = (pool_xml_elem_t *)src;
pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov;
if ((cb = alloc_char_buf(CB_DEFAULT_LEN)) == NULL)
return (NULL);
if (src_attr != NULL) {
char *tok;
char *lasts;
char *or = "";
xmlChar *id;
if (pool_is_xml_attr(prov->pxc_doc,
element_class_tags[src->pe_class], src_attr) != PO_TRUE) {
free_char_buf(cb);
pool_seterror(POE_BADPARAM);
return (NULL);
}
if ((id = xmlGetProp(pxe->pxe_node, BAD_CAST src_attr))
== NULL) {
free_char_buf(cb);
pool_seterror(POE_DATASTORE);
return (NULL);
}
for (tok = strtok_r((char *)id, " ", &lasts);
tok != NULL; tok = strtok_r(NULL, " ", &lasts)) {
(void) append_char_buf(cb, "%s//*[@ref_id=\"%s\"]",
or, tok);
or = " | ";
if ((classes & PEC_QRY_SYSTEM) != 0) {
if (pool_build_xpath_buf(prov, src, PEC_SYSTEM,
props, cb, PO_TRUE) == PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
if ((classes & PEC_QRY_POOL) != 0) {
if (pool_build_xpath_buf(prov, src, PEC_POOL,
props, cb, PO_TRUE) == PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
if ((classes & PEC_QRY_RES_COMP) != 0) {
if (pool_build_xpath_buf(prov, src,
PEC_RES_COMP, props, cb, PO_TRUE)
== PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
} else if ((classes & PEC_QRY_RES_AGG) != 0) {
if (pool_build_xpath_buf(prov, src,
PEC_RES_AGG, props, cb, PO_TRUE)
== PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
}
xmlFree(id);
} else {
if ((classes & PEC_QRY_SYSTEM) != 0) {
if (pool_build_xpath_buf(prov, src, PEC_SYSTEM, props,
cb, PO_FALSE) == PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
if ((classes & PEC_QRY_POOL) != 0) {
if (pool_build_xpath_buf(prov, src, PEC_POOL, props,
cb, PO_FALSE) == PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
if ((classes & PEC_QRY_RES_COMP) != 0) {
if (pool_build_xpath_buf(prov, src, PEC_RES_COMP, props,
cb, PO_FALSE) == PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
if ((classes & PEC_QRY_RES_AGG) != 0) {
if (pool_build_xpath_buf(prov, src, PEC_RES_AGG, props,
cb, PO_FALSE) == PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
if ((classes & PEC_QRY_COMP) != 0) {
if (pool_build_xpath_buf(prov, src, PEC_COMP, props,
cb, PO_FALSE) == PO_FAIL) {
free_char_buf(cb);
return (NULL);
}
}
}
buf = strdup(cb->cb_buf);
free_char_buf(cb);
if ((rs = pool_xml_result_set_alloc(conf)) == NULL) {
free(buf);
return (NULL);
}
if ((rs->pxr_ctx = xmlXPathNewContext(
((pool_xml_connection_t *)conf->pc_prov)->pxc_doc)) == NULL) {
free(buf);
(void) pool_xml_rs_close((pool_result_set_t *)rs);
pool_seterror(POE_DATASTORE);
return (NULL);
}
if (src == NULL)
rs->pxr_ctx->node = xmlDocGetRootElement
(((pool_xml_connection_t *)conf->pc_prov)->pxc_doc);
else
rs->pxr_ctx->node = pxe->pxe_node;
rs->pxr_path = xmlXPathEval(BAD_CAST buf, rs->pxr_ctx);
free(buf);
if (rs->pxr_path->nodesetval->nodeNr == 0)
pool_seterror(POE_INVALID_SEARCH);
return ((pool_result_set_t *)rs);
}
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)
{
int i;
const char *ATTR_FMTS[] = {
"[ @%s=\"%llu\" ]",
"[ @%s=\"%lld\" ]",
"[ @%s=\"%f\" ]",
"[ @%s=\"%s\" ]",
"[ @%s=\"%s\" ]",
};
const char *PROP_FMTS[] = {
"[ property[@name=\"%s\"][text()=\"%llu\"] ]",
"[ property[@name=\"%s\"][text()=\"%lld\"] ]",
"[ property[@name=\"%s\"][text()=\"%f\"] ]",
"[ property[@name=\"%s\"][text()=\"%s\"] ]",
"[ property[@name=\"%s\"][text()=\"%s\"] ]"
};
const char **fmts;
int nprop;
const char *last_prop_name = NULL;
char *type_prefix = NULL;
int has_type = PO_FALSE;
if (is_ref == PO_FALSE) {
if (cb->cb_buf != NULL && strlen(cb->cb_buf) > 0)
(void) append_char_buf(cb, " |");
if (src != NULL)
(void) append_char_buf(cb, " ./");
else
(void) append_char_buf(cb, "//");
(void) append_char_buf(cb, element_class_tags[class]);
}
if (props == NULL || props[0] == NULL)
return (PO_SUCCESS);
for (nprop = 0; props[nprop] != NULL; nprop++)
;
qsort(props, nprop, sizeof (pool_value_t *), prop_sort);
for (i = 0; i < nprop; i++) {
int is_attr = 0;
const char *prefix;
const char *prop_name;
uint64_t uval;
int64_t ival;
double dval;
uchar_t bval;
const char *sval;
pool_value_class_t pvc;
prop_name = pool_value_get_name(props[i]);
if ((prefix = is_a_known_prefix(class, prop_name)) != NULL) {
const char *attr_name;
if (strcmp(prop_name, c_type) == 0) {
has_type = PO_TRUE;
attr_name = prop_name;
} else
attr_name = prop_name + strlen(prefix) + 1;
if (pool_is_xml_attr(prov->pxc_doc,
element_class_tags[class], attr_name)) {
is_attr = 1;
prop_name = attr_name;
if (class == PEC_RES_COMP ||
class == PEC_RES_AGG ||
class == PEC_COMP) {
if (type_prefix != NULL)
free(type_prefix);
type_prefix = strdup(prefix);
}
}
}
if (is_attr) {
fmts = ATTR_FMTS;
} else {
fmts = PROP_FMTS;
}
switch ((pvc = pool_value_get_type(props[i]))) {
case POC_UINT:
(void) pool_value_get_uint64(props[i], &uval);
if (append_char_buf(cb, fmts[pvc], prop_name, uval)
== PO_FAIL) {
free(type_prefix);
return (PO_FAIL);
}
break;
case POC_INT:
(void) pool_value_get_int64(props[i], &ival);
if (append_char_buf(cb, fmts[pvc], prop_name, ival)
== PO_FAIL) {
free(type_prefix);
return (PO_FAIL);
}
break;
case POC_DOUBLE:
(void) pool_value_get_double(props[i], &dval);
if (append_char_buf(cb, fmts[pvc], prop_name, dval)
== PO_FAIL) {
free(type_prefix);
return (PO_FAIL);
}
break;
case POC_BOOL:
(void) pool_value_get_bool(props[i], &bval);
if (append_char_buf(cb, fmts[pvc], prop_name,
bval ? "true" : "false") == PO_FAIL) {
free(type_prefix);
return (PO_FAIL);
}
break;
case POC_STRING:
(void) pool_value_get_string(props[i], &sval);
if (append_char_buf(cb, fmts[pvc], prop_name, sval)
== PO_FAIL) {
free(type_prefix);
return (PO_FAIL);
}
break;
default:
free(type_prefix);
pool_seterror(POE_INVALID_SEARCH);
return (PO_FAIL);
}
if (last_prop_name != NULL) {
const char *suffix1, *suffix2;
suffix1 = strrchr(prop_name, '.');
suffix2 = strrchr(last_prop_name, '.');
if (suffix1 != NULL || suffix2 != NULL) {
if (suffix1 == NULL)
suffix1 = prop_name;
else
suffix1++;
if (suffix2 == NULL)
suffix2 = last_prop_name;
else
suffix2++;
} else {
suffix1 = prop_name;
suffix2 = last_prop_name;
}
if (strcmp(suffix1, suffix2) == 0) {
char *where = strrchr(cb->cb_buf, '[');
if (is_attr != PO_TRUE) {
while (*--where != '[')
;
while (*--where != '[')
;
}
*(where - 1) = 'o';
*where = 'r';
}
}
last_prop_name = prop_name;
}
if (has_type == PO_FALSE) {
if (type_prefix) {
if (append_char_buf(cb, ATTR_FMTS[POC_STRING],
c_type, type_prefix) == PO_FAIL) {
free(type_prefix);
return (PO_FAIL);
}
}
}
free(type_prefix);
return (PO_SUCCESS);
}
static int
prop_sort(const void *a, const void *b)
{
pool_value_t **prop_a = (pool_value_t **)a;
pool_value_t **prop_b = (pool_value_t **)b;
const char *str_a;
const char *str_b;
const char *suffix1, *suffix2;
str_a = pool_value_get_name(*prop_a);
str_b = pool_value_get_name(*prop_b);
suffix1 = strrchr(str_a, '.');
suffix2 = strrchr(str_b, '.');
if (suffix1 != NULL || suffix2 != NULL) {
if (suffix1 == NULL)
suffix1 = str_a;
else
suffix1++;
if (suffix2 == NULL)
suffix2 = str_b;
else
suffix2++;
} else {
suffix1 = str_a;
suffix2 = str_b;
}
return (strcmp(suffix1, suffix2));
}
static int
dtd_exists(const char *path)
{
struct stat buf;
if (strstr(path, "file://") != path)
return (PO_FALSE);
if (path[7] == 0)
return (PO_FALSE);
if (stat(&path[7], &buf) == 0)
return (PO_TRUE);
return (PO_FALSE);
}
static void
build_dtype_accelerator(void)
{
xmlDtdPtr dtd;
const xmlChar *elem_list[ELEM_TYPE_COUNT] = {
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;
if ((dtd = xmlParseDTD(BAD_CAST "-//Sun Microsystems Inc//DTD Resource"
" Management All//EN", BAD_CAST dtd_location)) == NULL)
return;
for (i = 0; i < ELEM_TYPE_COUNT; i++) {
xmlElementPtr elem;
xmlAttributePtr attr;
if ((elem = xmlGetDtdElementDesc(dtd, elem_list[i])) == NULL)
return;
elem_tbl[i].ett_elem = xmlStrdup(elem->name);
for (attr = elem->attributes; attr != NULL;
attr = attr->nexth) {
if (strcmp((const char *)attr->name, c_a_dtype) == 0) {
elem_tbl[i].ett_dtype =
build_dtype_tbl(attr->defaultValue);
}
}
}
xmlFreeDtd(dtd);
}
static dtype_tbl_t
(*build_dtype_tbl(const xmlChar *rawdata))[]
{
char *tok;
char *lasts;
dtype_tbl_t (*tbl)[];
int j = 0;
xmlChar *data;
const int max_attr = 11;
if (rawdata == NULL)
return (NULL);
if ((data = xmlStrdup(rawdata)) == NULL)
return (NULL);
if ((tbl = calloc(max_attr, sizeof (dtype_tbl_t))) == NULL) {
xmlFree(data);
return (NULL);
}
for (tok = strtok_r((char *)data, " ", &lasts); tok != NULL;
tok = strtok_r(NULL, " ", &lasts)) {
int i;
(*tbl)[j].dt_name = xmlStrdup(BAD_CAST tok);
if ((tok = strtok_r(NULL, " ", &lasts)) == NULL) {
int k = j;
for (j = 0; j < k; j++)
free((*tbl)[j].dt_name);
pool_seterror(POE_DATASTORE);
xmlFree(data);
free(tbl);
return (NULL);
}
for (i = 0; i < (sizeof (data_type_tags) /
sizeof (data_type_tags[0])); i++) {
if (strcmp(tok, data_type_tags[i]) == 0)
(*tbl)[j++].dt_type = i;
}
if (j == max_attr) {
for (j = 0; j < max_attr; j++)
free((*tbl)[j].dt_name);
free(tbl);
xmlFree(data);
return (NULL);
}
}
(*tbl)[j].dt_name = NULL;
xmlFree(data);
return (tbl);
}
static int
get_fast_dtype(xmlNodePtr node, xmlChar *name)
{
int i;
xmlElementPtr elem;
if ((elem = xmlGetDtdElementDesc(node->doc->extSubset, node->name))
== NULL) {
pool_seterror(POE_BADPARAM);
return (POC_INVAL);
}
for (i = 0; i < ELEM_TYPE_COUNT; i++) {
if (xmlStrcmp(elem_tbl[i].ett_elem, elem->name) == 0) {
dtype_tbl_t (*tbl)[] = elem_tbl[i].ett_dtype;
int j = 0;
if (tbl == NULL)
break;
for (j = 0; (*tbl)[j].dt_name != NULL; j++)
if (xmlStrcmp(name, (*tbl)[j].dt_name) == 0)
return ((*tbl)[j].dt_type);
break;
}
}
return (POC_STRING);
}
static int
pool_xml_parse_document(pool_conf_t *conf)
{
int res;
char chars[PAGE_READ_SIZE];
struct stat f_stat;
xmlParserCtxtPtr ctxt;
size_t size;
pool_xml_connection_t *prov = (pool_xml_connection_t *)conf->pc_prov;
xmlNodePtr root;
pool_resource_t **rsl;
uint_t nelem;
int i;
if (fstat(fileno(prov->pxc_file), &f_stat) == -1) {
pool_seterror(POE_SYSTEM);
return (PO_FAIL);
}
if (f_stat.st_size == 0) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
} else
size = f_stat.st_size < 4 ? 4 : PAGE_READ_SIZE;
res = fread(chars, 1, size, prov->pxc_file);
if (res >= 4) {
xmlValidCtxtPtr cvp;
if ((ctxt = xmlCreatePushParserCtxt(NULL, NULL,
chars, res, conf->pc_location)) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
xmlCtxtUseOptions(ctxt,
XML_PARSE_DTDLOAD | XML_PARSE_DTDVALID |
XML_PARSE_NOBLANKS);
while ((res = fread(chars, 1, size, prov->pxc_file)) > 0) {
if (xmlParseChunk(ctxt, chars, res, 0) != 0) {
xmlFreeParserCtxt(ctxt);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
}
if (xmlParseChunk(ctxt, chars, 0, 1) != 0) {
xmlFreeParserCtxt(ctxt);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
if ((cvp = xmlNewValidCtxt()) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
cvp->error = pool_error_func;
cvp->warning = pool_error_func;
if (xmlValidateDocument(cvp, ctxt->myDoc) == 0) {
xmlFreeValidCtxt(cvp);
xmlFreeParserCtxt(ctxt);
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
prov->pxc_doc = ctxt->myDoc;
xmlFreeValidCtxt(cvp);
xmlFreeParserCtxt(ctxt);
}
if (prov->pxc_doc == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
prov->pxc_doc->_private = conf;
if ((root = xmlDocGetRootElement(prov->pxc_doc)) == NULL) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
if (create_shadow(root) != PO_SUCCESS) {
pool_seterror(POE_INVALID_CONF);
return (PO_FAIL);
}
if (pool_xml_validate(conf, POV_STRICT) != PO_SUCCESS) {
return (PO_FAIL);
}
if ((rsl = pool_query_resources(conf, &nelem, NULL)) != NULL) {
pool_value_t val = POOL_VALUE_INITIALIZER;
for (i = 0; i < nelem; i++) {
if (pool_get_ns_property(TO_ELEM(rsl[i]), c_size_prop,
&val) != POC_UINT) {
pool_component_t **cs;
uint_t size;
if ((cs = pool_query_resource_components(conf,
rsl[i], &size, NULL)) != NULL) {
free(cs);
pool_value_set_uint64(&val, size);
} else
pool_value_set_uint64(&val, 0);
if (pool_put_any_ns_property(TO_ELEM(rsl[i]),
c_size_prop, &val) != PO_SUCCESS) {
free(rsl);
return (PO_FAIL);
}
}
}
free(rsl);
}
return (PO_SUCCESS);
}