Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
po/POTFILES.in | 1 +
src/Makefile.am | 5 +
src/conf/fs_conf.c | 1624 ++++++++++++++++++++++++++++++++++++++++++++++
src/conf/fs_conf.h | 310 +++++++++
src/libvirt_private.syms | 42 ++
5 files changed, 1982 insertions(+)
create mode 100644 src/conf/fs_conf.c
create mode 100644 src/conf/fs_conf.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index af00155..f4d2f25 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -25,6 +25,7 @@ src/conf/domain_addr.c
src/conf/domain_capabilities.c
src/conf/domain_conf.c
src/conf/domain_event.c
+src/conf/fs_conf.c
src/conf/interface_conf.c
src/conf/netdev_bandwidth_conf.c
src/conf/netdev_vlan_conf.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 8fc6582..db69fbb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -397,6 +397,10 @@ CHRDEV_CONF_SOURCES = \
DEVICE_CONF_SOURCES = \
conf/device_conf.c conf/device_conf.h
+# FS driver generic impl APIs
+FS_CONF_SOURCES = \
+ conf/fs_conf.h conf/fs_conf.c
+
CONF_SOURCES = \
$(NETDEV_CONF_SOURCES) \
$(DOMAIN_CONF_SOURCES) \
@@ -409,6 +413,7 @@ CONF_SOURCES = \
$(NWFILTER_CONF_SOURCES) \
$(NODE_DEVICE_CONF_SOURCES) \
$(STORAGE_CONF_SOURCES) \
+ $(FS_CONF_SOURCES) \
$(INTERFACE_CONF_SOURCES) \
$(SECRET_CONF_SOURCES) \
$(CPU_CONF_SOURCES) \
diff --git a/src/conf/fs_conf.c b/src/conf/fs_conf.c
new file mode 100644
index 0000000..4906c86
--- /dev/null
+++ b/src/conf/fs_conf.c
@@ -0,0 +1,1624 @@
+/*
+ * fs_conf.c: config handling for fs driver
+ *
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "virerror.h"
+#include "datatypes.h"
+#include "fs_conf.h"
+
+#include "virxml.h"
+#include "viruuid.h"
+#include "virbuffer.h"
+#include "viralloc.h"
+#include "virfile.h"
+#include "virstring.h"
+#include "virlog.h"
+
+#define VIR_FROM_THIS VIR_FROM_FSPOOL
+
+VIR_LOG_INIT("conf.fs_conf");
+
+VIR_ENUM_IMPL(virFsPool,
+ VIR_FS_POOL_LAST,
+ "dir")
+
+VIR_ENUM_IMPL(virFsItem,
+ VIR_FS_ITEM_LAST,
+ "dir")
+
+/* Flags to indicate mandatory components in the fspool source */
+enum {
+ VIR_FS_POOL_SOURCE_DIR = (1 << 2),
+ VIR_FS_POOL_SOURCE_NAME = (1 << 4),
+ VIR_FS_POOL_SOURCE_NETWORK = (1 << 6),
+};
+
+typedef const char *(*virFsItemFormatToString)(int format);
+typedef int (*virFsItemFormatFromString)(const char *format);
+
+typedef const char *(*virFsPoolFormatToString)(int format);
+typedef int (*virFsPoolFormatFromString)(const char *format);
+
+typedef struct _virFsItemOptions virFsItemOptions;
+typedef virFsItemOptions *virFsItemOptionsPtr;
+struct _virFsItemOptions {
+ int defaultFormat;
+ virFsItemFormatToString formatToString;
+ virFsItemFormatFromString formatFromString;
+};
+
+typedef struct _virFsPoolOptions virFsPoolOptions;
+typedef virFsPoolOptions *virFsPoolOptionsPtr;
+struct _virFsPoolOptions {
+ unsigned int flags;
+ int defaultFormat;
+ virFsPoolFormatToString formatToString;
+ virFsPoolFormatFromString formatFromString;
+};
+
+typedef struct _virFsPoolTypeInfo virFsPoolTypeInfo;
+typedef virFsPoolTypeInfo *virFsPoolTypeInfoPtr;
+struct _virFsPoolTypeInfo {
+ int fspoolType;
+ virFsPoolOptions fspoolOptions;
+ virFsItemOptions itemOptions;
+};
+
+static virFsPoolTypeInfo fspoolTypeInfo[] = {
+ {.fspoolType = VIR_FS_POOL_DIR}
+};
+
+
+static virFsPoolTypeInfoPtr
+virFsPoolTypeInfoLookup(int type)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_CARDINALITY(fspoolTypeInfo); i++)
+ if (fspoolTypeInfo[i].fspoolType == type)
+ return &fspoolTypeInfo[i];
+
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("missing backend for fspool type %d"), type);
+ return NULL;
+}
+
+static virFsPoolOptionsPtr
+virFsPoolOptionsForPoolType(int type)
+{
+ virFsPoolTypeInfoPtr backend = virFsPoolTypeInfoLookup(type);
+ if (backend == NULL)
+ return NULL;
+ return &backend->fspoolOptions;
+}
+
+static virFsItemOptionsPtr
+virFsItemOptionsForPoolType(int type)
+{
+ virFsPoolTypeInfoPtr backend = virFsPoolTypeInfoLookup(type);
+ if (backend == NULL)
+ return NULL;
+ return &backend->itemOptions;
+}
+
+static void
+virFsSourcePoolDefFree(virFsSourcePoolDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->pool);
+ VIR_FREE(def->item);
+
+ VIR_FREE(def);
+}
+
+static void
+virFsPermsFree(virFsPermsPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->label);
+ VIR_FREE(def);
+}
+
+static void
+virFsSourceClear(virFsSourcePtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->path);
+ virFsSourcePoolDefFree(def->srcpool);
+ VIR_FREE(def->driverName);
+ virFsPermsFree(def->perms);
+}
+
+void
+virFsItemDefFree(virFsItemDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+ VIR_FREE(def->key);
+
+ virFsSourceClear(&def->target);
+ VIR_FREE(def);
+}
+
+void
+virFsPoolSourceClear(virFsPoolSourcePtr source)
+{
+ if (!source)
+ return;
+
+ VIR_FREE(source->dir);
+ VIR_FREE(source->name);
+ VIR_FREE(source->vendor);
+ VIR_FREE(source->product);
+}
+
+void
+virFsPoolSourceFree(virFsPoolSourcePtr source)
+{
+ virFsPoolSourceClear(source);
+ VIR_FREE(source);
+}
+
+void
+virFsPoolDefFree(virFsPoolDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def->name);
+
+ virFsPoolSourceClear(&def->source);
+
+ VIR_FREE(def->target.path);
+ VIR_FREE(def->target.perms.label);
+ VIR_FREE(def);
+}
+
+void
+virFsPoolObjFree(virFsPoolObjPtr obj)
+{
+ if (!obj)
+ return;
+
+ virFsPoolObjClearItems(obj);
+
+ virFsPoolDefFree(obj->def);
+ virFsPoolDefFree(obj->newDef);
+
+ VIR_FREE(obj->configFile);
+ VIR_FREE(obj->autostartLink);
+
+ virMutexDestroy(&obj->lock);
+
+ VIR_FREE(obj);
+}
+
+void
+virFsPoolObjListFree(virFsPoolObjListPtr fspools)
+{
+ size_t i;
+ for (i = 0; i < fspools->count; i++)
+ virFsPoolObjFree(fspools->objs[i]);
+ VIR_FREE(fspools->objs);
+ fspools->count = 0;
+}
+
+void
+virFsPoolObjRemove(virFsPoolObjListPtr fspools,
+ virFsPoolObjPtr fspool)
+{
+ size_t i;
+
+ virFsPoolObjUnlock(fspool);
+
+ for (i = 0; i < fspools->count; i++) {
+ virFsPoolObjLock(fspools->objs[i]);
+ if (fspools->objs[i] == fspool) {
+ virFsPoolObjUnlock(fspools->objs[i]);
+ virFsPoolObjFree(fspools->objs[i]);
+
+ VIR_DELETE_ELEMENT(fspools->objs, i, fspools->count);
+ break;
+ }
+ virFsPoolObjUnlock(fspools->objs[i]);
+ }
+}
+
+static int
+virFsPoolDefParseSource(xmlXPathContextPtr ctxt,
+ virFsPoolSourcePtr source,
+ int fspool_type,
+ xmlNodePtr node)
+{
+ int ret = -1;
+ xmlNodePtr relnode /*, authnode, *nodeset = NULL*/;
+ virFsPoolOptionsPtr options;
+
+ relnode = ctxt->node;
+ ctxt->node = node;
+
+ if ((options = virFsPoolOptionsForPoolType(fspool_type)) == NULL)
+ goto cleanup;
+
+ source->name = virXPathString("string(./name)", ctxt);
+
+ if (options->formatFromString) {
+ char *format = virXPathString("string(./format/@type)", ctxt);
+ if (format == NULL)
+ source->format = options->defaultFormat;
+ else
+ source->format = options->formatFromString(format);
+
+ if (source->format < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown fspool format type %s"), format);
+ VIR_FREE(format);
+ goto cleanup;
+ }
+ VIR_FREE(format);
+ }
+
+ source->dir = virXPathString("string(./dir/@path)", ctxt);
+
+ source->vendor = virXPathString("string(./vendor/@name)", ctxt);
+ source->product = virXPathString("string(./product/@name)", ctxt);
+
+ ret = 0;
+ cleanup:
+ ctxt->node = relnode;
+
+ return ret;
+}
+
+virFsPoolSourcePtr
+virFsPoolDefParseSourceString(const char *srcSpec,
+ int fspool_type)
+{
+ xmlDocPtr doc = NULL;
+ xmlNodePtr node = NULL;
+ xmlXPathContextPtr xpath_ctxt = NULL;
+ virFsPoolSourcePtr def = NULL, ret = NULL;
+
+ if (!(doc = virXMLParseStringCtxt(srcSpec,
+ _("(storage_source_specification)"),
+ &xpath_ctxt)))
+ goto cleanup;
+
+ if (VIR_ALLOC(def) < 0)
+ goto cleanup;
+
+ if (!(node = virXPathNode("/source", xpath_ctxt))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("root element was not source"));
+ goto cleanup;
+ }
+
+ if (virFsPoolDefParseSource(xpath_ctxt, def, fspool_type,
+ node) < 0)
+ goto cleanup;
+
+ ret = def;
+ def = NULL;
+ cleanup:
+ virFsPoolSourceFree(def);
+ xmlFreeDoc(doc);
+ xmlXPathFreeContext(xpath_ctxt);
+
+ return ret;
+}
+
+static int
+virFsDefParsePerms(xmlXPathContextPtr ctxt,
+ virFsPermsPtr perms,
+ const char *permxpath)
+{
+ char *mode;
+ long long val;
+ int ret = -1;
+ xmlNodePtr relnode;
+ xmlNodePtr node;
+
+ node = virXPathNode(permxpath, ctxt);
+ if (node == NULL) {
+ /* Set default values if there is not <permissions> element */
+ perms->mode = (mode_t) -1;
+ perms->uid = (uid_t) -1;
+ perms->gid = (gid_t) -1;
+ perms->label = NULL;
+ return 0;
+ }
+
+ relnode = ctxt->node;
+ ctxt->node = node;
+
+ if ((mode = virXPathString("string(./mode)", ctxt))) {
+ int tmp;
+
+ if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
+ VIR_FREE(mode);
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("malformed octal mode"));
+ goto error;
+ }
+ perms->mode = tmp;
+ VIR_FREE(mode);
+ } else {
+ perms->mode = (mode_t) -1;
+ }
+
+ if (virXPathNode("./owner", ctxt) == NULL) {
+ perms->uid = (uid_t) -1;
+ } else {
+ /* We previously could output -1, so continue to parse it */
+ if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 ||
+ ((uid_t)val != val &&
+ val != -1)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("malformed owner element"));
+ goto error;
+ }
+
+ perms->uid = val;
+ }
+
+ if (virXPathNode("./group", ctxt) == NULL) {
+ perms->gid = (gid_t) -1;
+ } else {
+ /* We previously could output -1, so continue to parse it */
+ if (virXPathLongLong("number(./group)", ctxt, &val) < 0 ||
+ ((gid_t) val != val &&
+ val != -1)) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("malformed group element"));
+ goto error;
+ }
+ perms->gid = val;
+ }
+
+ /* NB, we're ignoring missing labels here - they'll simply inherit */
+ perms->label = virXPathString("string(./label)", ctxt);
+
+ ret = 0;
+ error:
+ ctxt->node = relnode;
+ return ret;
+}
+
+static virFsPoolDefPtr
+virFsPoolDefParseXML(xmlXPathContextPtr ctxt)
+{
+ virFsPoolOptionsPtr options;
+ virFsPoolDefPtr ret;
+ xmlNodePtr source_node;
+ char *type = NULL;
+ char *uuid = NULL;
+ char *target_path = NULL;
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ type = virXPathString("string(./@type)", ctxt);
+ if (type == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("fspool missing type attribute"));
+ goto error;
+ }
+
+ if ((ret->type = virFsPoolTypeFromString(type)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown fspool type %s"), type);
+ goto error;
+ }
+
+ if ((options = virFsPoolOptionsForPoolType(ret->type)) == NULL)
+ goto error;
+
+ source_node = virXPathNode("./source", ctxt);
+ if (source_node) {
+ if (virFsPoolDefParseSource(ctxt, &ret->source, ret->type,
+ source_node) < 0)
+ goto error;
+ }
+
+ ret->name = virXPathString("string(./name)", ctxt);
+ if (ret->name == NULL &&
+ options->flags & VIR_FS_POOL_SOURCE_NAME)
+ ret->name = ret->source.name;
+ if (ret->name == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing pool source name element"));
+ goto error;
+ }
+
+ if (strchr(ret->name, '/')) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("name %s cannot contain '/'"), ret->name);
+ goto error;
+ }
+
+ uuid = virXPathString("string(./uuid)", ctxt);
+ if (uuid == NULL) {
+ if (virUUIDGenerate(ret->uuid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unable to generate uuid"));
+ goto error;
+ }
+ } else {
+ if (virUUIDParse(uuid, ret->uuid) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("malformed uuid element"));
+ goto error;
+ }
+ }
+
+
+ if (options->flags & VIR_FS_POOL_SOURCE_DIR) {
+ if (!ret->source.dir) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing storage pool source path"));
+ goto error;
+ }
+ }
+ if (options->flags & VIR_FS_POOL_SOURCE_NAME) {
+ if (ret->source.name == NULL) {
+ /* source name defaults to pool name */
+ if (VIR_STRDUP(ret->source.name, ret->name) < 0)
+ goto error;
+ }
+ }
+ target_path = virXPathString("string(./target/path)", ctxt);
+ if (!target_path) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing storage pool target path"));
+ goto error;
+ }
+ ret->target.path = virFileSanitizePath(target_path);
+ if (!ret->target.path)
+ goto error;
+
+ if (virFsDefParsePerms(ctxt, &ret->target.perms,
+ "./target/permissions") < 0)
+ goto error;
+
+ cleanup:
+ VIR_FREE(uuid);
+ VIR_FREE(type);
+ VIR_FREE(target_path);
+ return ret;
+
+ error:
+ virFsPoolDefFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+virFsPoolDefPtr
+virFsPoolDefParseNode(xmlDocPtr xml,
+ xmlNodePtr root)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virFsPoolDefPtr def = NULL;
+
+ if (!xmlStrEqual(root->name, BAD_CAST "fspool")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unexpected root element <%s>, "
+ "expecting <fspool>"),
+ root->name);
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ def = virFsPoolDefParseXML(ctxt);
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
+
+static virFsPoolDefPtr
+virFsPoolDefParse(const char *xmlStr,
+ const char *filename)
+{
+ virFsPoolDefPtr ret = NULL;
+ xmlDocPtr xml;
+
+ if ((xml = virXMLParse(filename, xmlStr, _("(fs_pool_definition)")))) {
+ ret = virFsPoolDefParseNode(xml, xmlDocGetRootElement(xml));
+ xmlFreeDoc(xml);
+ }
+
+ return ret;
+}
+
+virFsPoolDefPtr
+virFsPoolDefParseString(const char *xmlStr)
+{
+ return virFsPoolDefParse(xmlStr, NULL);
+}
+
+virFsPoolDefPtr
+virFsPoolDefParseFile(const char *filename)
+{
+ return virFsPoolDefParse(NULL, filename);
+}
+
+static int
+virFsPoolSourceFormat(virBufferPtr buf,
+ virFsPoolOptionsPtr options,
+ virFsPoolSourcePtr src)
+{
+
+ virBufferAddLit(buf, "<source>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ if (options->flags & VIR_FS_POOL_SOURCE_DIR)
+ virBufferEscapeString(buf, "<dir path='%s'/>\n",
src->dir);
+
+ if (options->flags & VIR_FS_POOL_SOURCE_NAME)
+ virBufferEscapeString(buf, "<name>%s</name>\n",
src->name);
+
+ if (options->formatToString) {
+ const char *format = (options->formatToString)(src->format);
+ if (!format) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown pool format number %d"),
+ src->format);
+ return -1;
+ }
+ virBufferAsprintf(buf, "<format type='%s'/>\n", format);
+ }
+
+
+ virBufferEscapeString(buf, "<vendor name='%s'/>\n",
src->vendor);
+ virBufferEscapeString(buf, "<product name='%s'/>\n",
src->product);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</source>\n");
+ return 0;
+}
+
+
+static int
+virFsPoolDefFormatBuf(virBufferPtr buf,
+ virFsPoolDefPtr def)
+{
+ virFsPoolOptionsPtr options;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ const char *type;
+
+ options = virFsPoolOptionsForPoolType(def->type);
+ if (options == NULL)
+ return -1;
+
+ type = virFsPoolTypeToString(def->type);
+ if (!type) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unexpected fspool type"));
+ return -1;
+ }
+ virBufferAsprintf(buf, "<fspool type='%s'>\n", type);
+ virBufferAdjustIndent(buf, 2);
+ virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
+
+ virUUIDFormat(def->uuid, uuid);
+ virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuid);
+
+ virBufferAsprintf(buf, "<capacity
unit='bytes'>%llu</capacity>\n",
+ def->capacity);
+ virBufferAsprintf(buf, "<allocation
unit='bytes'>%llu</allocation>\n",
+ def->allocation);
+ virBufferAsprintf(buf, "<available
unit='bytes'>%llu</available>\n",
+ def->available);
+
+ if (virFsPoolSourceFormat(buf, options, &def->source) < 0)
+ return -1;
+
+ virBufferAddLit(buf, "<target>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ virBufferEscapeString(buf, "<path>%s</path>\n",
def->target.path);
+
+ if (def->target.perms.mode != (mode_t) -1 ||
+ def->target.perms.uid != (uid_t) -1 ||
+ def->target.perms.gid != (gid_t) -1 ||
+ def->target.perms.label) {
+ virBufferAddLit(buf, "<permissions>\n");
+ virBufferAdjustIndent(buf, 2);
+ if (def->target.perms.mode != (mode_t) -1)
+ virBufferAsprintf(buf, "<mode>0%o</mode>\n",
+ def->target.perms.mode);
+ if (def->target.perms.uid != (uid_t) -1)
+ virBufferAsprintf(buf, "<owner>%d</owner>\n",
+ (int) def->target.perms.uid);
+ if (def->target.perms.gid != (gid_t) -1)
+ virBufferAsprintf(buf, "<group>%d</group>\n",
+ (int) def->target.perms.gid);
+ virBufferEscapeString(buf, "<label>%s</label>\n",
+ def->target.perms.label);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</permissions>\n");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</target>\n");
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</fspool>\n");
+
+ return 0;
+}
+
+char *
+virFsPoolDefFormat(virFsPoolDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (virFsPoolDefFormatBuf(&buf, def) < 0)
+ goto error;
+
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
+
+ return virBufferContentAndReset(&buf);
+
+ error:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+
+static int
+virFsSize(const char *unit,
+ const char *val,
+ unsigned long long *ret)
+{
+ if (virStrToLong_ull(val, NULL, 10, ret) < 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("malformed capacity element"));
+ return -1;
+ }
+ /* off_t is signed, so you cannot create a file larger than 2**63
+ * bytes in the first place. */
+ if (virScaleInteger(ret, unit, 1, LLONG_MAX) < 0)
+ return -1;
+
+ return 0;
+}
+
+static virFsItemDefPtr
+virFsItemDefParseXML(virFsPoolDefPtr fspool,
+ xmlXPathContextPtr ctxt,
+ unsigned int flags)
+{
+ virFsItemDefPtr ret;
+ virFsItemOptionsPtr options;
+ char *type = NULL;
+ char *allocation = NULL;
+ char *capacity = NULL;
+ char *unit = NULL;
+ xmlNodePtr *nodes = NULL;
+
+ virCheckFlags(VIR_ITEM_XML_PARSE_NO_CAPACITY |
+ VIR_ITEM_XML_PARSE_OPT_CAPACITY, NULL);
+
+ options = virFsItemOptionsForPoolType(fspool->type);
+ if (options == NULL)
+ return NULL;
+
+ if (VIR_ALLOC(ret) < 0)
+ return NULL;
+
+ ret->name = virXPathString("string(./name)", ctxt);
+ if (ret->name == NULL) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing item name element"));
+ goto error;
+ }
+
+ /* Normally generated by pool refresh, but useful for unit tests */
+ ret->key = virXPathString("string(./key)", ctxt);
+
+ /* Technically overridden by pool refresh, but useful for unit tests */
+ type = virXPathString("string(./@type)", ctxt);
+ if (type) {
+ if ((ret->type = virFsItemTypeFromString(type)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown item type '%s'"), type);
+ goto error;
+ }
+ }
+
+ capacity = virXPathString("string(./capacity)", ctxt);
+ unit = virXPathString("string(./capacity/@unit)", ctxt);
+ if (capacity) {
+ if (virFsSize(unit, capacity, &ret->target.capacity) < 0)
+ goto error;
+ } else if (!(flags & VIR_ITEM_XML_PARSE_NO_CAPACITY) &&
+ !((flags & VIR_ITEM_XML_PARSE_OPT_CAPACITY))) {
+ virReportError(VIR_ERR_XML_ERROR, "%s", _("missing capacity
element"));
+ goto error;
+ }
+ VIR_FREE(unit);
+
+ allocation = virXPathString("string(./allocation)", ctxt);
+ if (allocation) {
+ unit = virXPathString("string(./allocation/@unit)", ctxt);
+ if (virFsSize(unit, allocation, &ret->target.allocation) < 0)
+ goto error;
+ } else {
+ ret->target.allocation = ret->target.capacity;
+ }
+
+ ret->target.path = virXPathString("string(./target/path)", ctxt);
+
+ if (VIR_ALLOC(ret->target.perms) < 0)
+ goto error;
+ if (virFsDefParsePerms(ctxt, ret->target.perms,
+ "./target/permissions") < 0)
+ goto error;
+
+ cleanup:
+ VIR_FREE(nodes);
+ VIR_FREE(allocation);
+ VIR_FREE(capacity);
+ VIR_FREE(unit);
+ VIR_FREE(type);
+ return ret;
+
+ error:
+ virFsItemDefFree(ret);
+ ret = NULL;
+ goto cleanup;
+}
+
+virFsItemDefPtr
+virFsItemDefParseNode(virFsPoolDefPtr fspool,
+ xmlDocPtr xml,
+ xmlNodePtr root,
+ unsigned int flags)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ virFsItemDefPtr def = NULL;
+
+ if (!xmlStrEqual(root->name, BAD_CAST "item")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unexpected root element <%s>, "
+ "expecting <item>"),
+ root->name);
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ctxt->node = root;
+ def = virFsItemDefParseXML(fspool, ctxt, flags);
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ return def;
+}
+
+static virFsItemDefPtr
+virFsItemDefParse(virFsPoolDefPtr fspool,
+ const char *xmlStr,
+ const char *filename,
+ unsigned int flags)
+{
+ virFsItemDefPtr ret = NULL;
+ xmlDocPtr xml;
+
+ if ((xml = virXMLParse(filename, xmlStr, _("(fspool_item_definition)"))))
{
+ ret = virFsItemDefParseNode(fspool, xml, xmlDocGetRootElement(xml), flags);
+ xmlFreeDoc(xml);
+ }
+
+ return ret;
+}
+
+virFsItemDefPtr
+virFsItemDefParseString(virFsPoolDefPtr fspool,
+ const char *xmlStr,
+ unsigned int flags)
+{
+ return virFsItemDefParse(fspool, xmlStr, NULL, flags);
+}
+
+virFsItemDefPtr
+virFsItemDefParseFile(virFsPoolDefPtr fspool,
+ const char *filename,
+ unsigned int flags)
+{
+ return virFsItemDefParse(fspool, NULL, filename, flags);
+}
+
+static int
+virFsItemTargetDefFormat(virFsItemOptionsPtr options ATTRIBUTE_UNUSED,
+ virBufferPtr buf,
+ virFsSourcePtr def,
+ const char *type)
+{
+ virBufferAsprintf(buf, "<%s>\n", type);
+ virBufferAdjustIndent(buf, 2);
+
+ if (def->perms &&
+ (def->perms->mode != (mode_t) -1 ||
+ def->perms->uid != (uid_t) -1 ||
+ def->perms->gid != (gid_t) -1 ||
+ def->perms->label)) {
+ virBufferAddLit(buf, "<permissions>\n");
+ virBufferAdjustIndent(buf, 2);
+
+ if (def->perms->mode != (mode_t) -1)
+ virBufferAsprintf(buf, "<mode>0%o</mode>\n",
+ def->perms->mode);
+ if (def->perms->uid != (uid_t) -1)
+ virBufferAsprintf(buf, "<owner>%d</owner>\n",
+ (int) def->perms->uid);
+ if (def->perms->gid != (gid_t) -1)
+ virBufferAsprintf(buf, "<group>%d</group>\n",
+ (int) def->perms->gid);
+
+ virBufferEscapeString(buf, "<label>%s</label>\n",
+ def->perms->label);
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</permissions>\n");
+ }
+
+ virBufferAdjustIndent(buf, -2);
+ virBufferAsprintf(buf, "</%s>\n", type);
+ return 0;
+}
+
+char *
+virFsItemDefFormat(virFsPoolDefPtr fspool,
+ virFsItemDefPtr def)
+{
+ virFsItemOptionsPtr options;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ options = virFsItemOptionsForPoolType(fspool->type);
+ if (options == NULL)
+ return NULL;
+
+ virBufferAddLit(&buf, "<item>\n");
+ virBufferAdjustIndent(&buf, 2);
+
+ virBufferEscapeString(&buf, "<name>%s</name>\n",
def->name);
+ virBufferEscapeString(&buf, "<key>%s</key>\n",
def->key);
+
+ virBufferAsprintf(&buf, "<capacity
unit='bytes'>%llu</capacity>\n",
+ def->target.capacity);
+ virBufferAsprintf(&buf, "<allocation
unit='bytes'>%llu</allocation>\n",
+ def->target.allocation);
+
+ if (virFsItemTargetDefFormat(options, &buf,
+ &def->target, "target") < 0)
+ goto cleanup;
+
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</item>\n");
+
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
+
+ return virBufferContentAndReset(&buf);
+
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+
+virFsPoolObjPtr
+virFsPoolObjFindByUUID(virFsPoolObjListPtr fspools,
+ const unsigned char *uuid)
+{
+ size_t i;
+
+ for (i = 0; i < fspools->count; i++) {
+ virFsPoolObjLock(fspools->objs[i]);
+ if (!memcmp(fspools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
+ return fspools->objs[i];
+ virFsPoolObjUnlock(fspools->objs[i]);
+ }
+
+ return NULL;
+}
+
+virFsPoolObjPtr
+virFsPoolObjFindByName(virFsPoolObjListPtr fspools,
+ const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < fspools->count; i++) {
+ virFsPoolObjLock(fspools->objs[i]);
+ if (STREQ(fspools->objs[i]->def->name, name))
+ return fspools->objs[i];
+ virFsPoolObjUnlock(fspools->objs[i]);
+ }
+
+ return NULL;
+}
+
+
+void
+virFsPoolObjClearItems(virFsPoolObjPtr fspool)
+{
+ size_t i;
+ for (i = 0; i < fspool->items.count; i++)
+ virFsItemDefFree(fspool->items.objs[i]);
+
+ VIR_FREE(fspool->items.objs);
+ fspool->items.count = 0;
+}
+
+virFsItemDefPtr
+virFsItemDefFindByKey(virFsPoolObjPtr fspool,
+ const char *key)
+{
+ size_t i;
+
+ for (i = 0; i < fspool->items.count; i++)
+ if (STREQ(fspool->items.objs[i]->key, key))
+ return fspool->items.objs[i];
+
+ return NULL;
+}
+
+virFsItemDefPtr
+virFsItemDefFindByPath(virFsPoolObjPtr fspool,
+ const char *path)
+{
+ size_t i;
+
+ for (i = 0; i < fspool->items.count; i++)
+ if (STREQ(fspool->items.objs[i]->target.path, path))
+ return fspool->items.objs[i];
+
+ return NULL;
+}
+
+virFsItemDefPtr
+virFsItemDefFindByName(virFsPoolObjPtr fspool,
+ const char *name)
+{
+ size_t i;
+
+ for (i = 0; i < fspool->items.count; i++)
+ if (STREQ(fspool->items.objs[i]->name, name))
+ return fspool->items.objs[i];
+
+ return NULL;
+}
+
+virFsPoolObjPtr
+virFsPoolObjAssignDef(virFsPoolObjListPtr fspools,
+ virFsPoolDefPtr def)
+{
+ virFsPoolObjPtr fspool;
+
+ if ((fspool = virFsPoolObjFindByName(fspools, def->name))) {
+ if (!virFsPoolObjIsActive(fspool)) {
+ virFsPoolDefFree(fspool->def);
+ fspool->def = def;
+ } else {
+ virFsPoolDefFree(fspool->newDef);
+ fspool->newDef = def;
+ }
+ return fspool;
+ }
+
+ if (VIR_ALLOC(fspool) < 0)
+ return NULL;
+
+ if (virMutexInit(&fspool->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot initialize mutex"));
+ VIR_FREE(fspool);
+ return NULL;
+ }
+ virFsPoolObjLock(fspool);
+ fspool->active = 0;
+
+ if (VIR_APPEND_ELEMENT_COPY(fspools->objs, fspools->count, fspool) < 0) {
+ virFsPoolObjUnlock(fspool);
+ virFsPoolObjFree(fspool);
+ return NULL;
+ }
+ fspool->def = def;
+
+ return fspool;
+}
+
+static virFsPoolObjPtr
+virFsPoolObjLoad(virFsPoolObjListPtr fspools,
+ const char *file,
+ const char *path,
+ const char *autostartLink)
+{
+ virFsPoolDefPtr def;
+ virFsPoolObjPtr fspool;
+
+ if (!(def = virFsPoolDefParseFile(path)))
+ return NULL;
+
+ if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Storage fspool config filename '%s' does "
+ "not match fspool name '%s'"),
+ path, def->name);
+ virFsPoolDefFree(def);
+ return NULL;
+ }
+
+ if (!(fspool = virFsPoolObjAssignDef(fspools, def))) {
+ virFsPoolDefFree(def);
+ return NULL;
+ }
+
+ VIR_FREE(fspool->configFile); /* for driver reload */
+ if (VIR_STRDUP(fspool->configFile, path) < 0) {
+ virFsPoolObjRemove(fspools, fspool);
+ return NULL;
+ }
+ VIR_FREE(fspool->autostartLink); /* for driver reload */
+ if (VIR_STRDUP(fspool->autostartLink, autostartLink) < 0) {
+ virFsPoolObjRemove(fspools, fspool);
+ return NULL;
+ }
+
+ fspool->autostart = virFileLinkPointsTo(fspool->autostartLink,
+ fspool->configFile);
+
+ return fspool;
+}
+
+
+virFsPoolObjPtr
+virFsPoolLoadState(virFsPoolObjListPtr fspools,
+ const char *stateDir,
+ const char *name)
+{
+ char *stateFile = NULL;
+ virFsPoolDefPtr def = NULL;
+ virFsPoolObjPtr fspool = NULL;
+ xmlDocPtr xml = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ xmlNodePtr node = NULL;
+
+ if (!(stateFile = virFileBuildPath(stateDir, name, ".xml")))
+ goto error;
+
+ if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(fspool state)"),
&ctxt)))
+ goto error;
+
+ if (!(node = virXPathNode("//fspool", ctxt))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Could not find any 'fspool' element in state
file"));
+ goto error;
+ }
+
+ ctxt->node = node;
+ if (!(def = virFsPoolDefParseXML(ctxt)))
+ goto error;
+
+ if (STRNEQ(name, def->name)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Storage fspool state file '%s' does not match
"
+ "fspool name '%s'"),
+ stateFile, def->name);
+ goto error;
+ }
+
+ /* create the object */
+ if (!(fspool = virFsPoolObjAssignDef(fspools, def)))
+ goto error;
+
+ /* XXX: future handling of some additional useful status data,
+ * for now, if a status file for a fspool exists, the fspool will be marked
+ * as active
+ */
+
+ fspool->active = 1;
+
+ cleanup:
+ VIR_FREE(stateFile);
+ xmlFreeDoc(xml);
+ xmlXPathFreeContext(ctxt);
+ return fspool;
+
+ error:
+ virFsPoolDefFree(def);
+ goto cleanup;
+}
+
+
+int
+virFsPoolLoadAllState(virFsPoolObjListPtr fspools,
+ const char *stateDir)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int ret = -1;
+ int rc;
+
+ if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
+ return rc;
+
+ while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
+ virFsPoolObjPtr fspool;
+
+ if (!virFileStripSuffix(entry->d_name, ".xml"))
+ continue;
+
+ if (!(fspool = virFsPoolLoadState(fspools, stateDir, entry->d_name)))
+ continue;
+ virFsPoolObjUnlock(fspool);
+ }
+
+ VIR_DIR_CLOSE(dir);
+ return ret;
+}
+
+
+int
+virFsPoolLoadAllConfigs(virFsPoolObjListPtr fspools,
+ const char *configDir,
+ const char *autostartDir)
+{
+ DIR *dir;
+ struct dirent *entry;
+ int ret;
+ int rc;
+
+ if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
+ return rc;
+
+ while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
+ char *path;
+ char *autostartLink;
+ virFsPoolObjPtr fspool;
+
+ if (!virFileHasSuffix(entry->d_name, ".xml"))
+ continue;
+
+ if (!(path = virFileBuildPath(configDir, entry->d_name, NULL)))
+ continue;
+
+ if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
+ NULL))) {
+ VIR_FREE(path);
+ continue;
+ }
+
+ fspool = virFsPoolObjLoad(fspools, entry->d_name, path,
+ autostartLink);
+ if (fspool)
+ virFsPoolObjUnlock(fspool);
+
+ VIR_FREE(path);
+ VIR_FREE(autostartLink);
+ }
+
+ VIR_DIR_CLOSE(dir);
+ return ret;
+}
+
+
+static int virFsPoolSaveXML(const char *path,
+ virFsPoolDefPtr def,
+ const char *xml)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ int ret = -1;
+
+ virUUIDFormat(def->uuid, uuidstr);
+ ret = virXMLSaveFile(path,
+ virXMLPickShellSafeComment(def->name, uuidstr),
+ "fspool-edit", xml);
+
+ return ret;
+}
+
+
+int
+virFsPoolSaveState(const char *stateFile,
+ virFsPoolDefPtr def)
+{
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ int ret = -1;
+ char *xml;
+
+ virBufferAddLit(&buf, "<fspoolstate>\n");
+ virBufferAdjustIndent(&buf, 2);
+
+ if (virFsPoolDefFormatBuf(&buf, def) < 0)
+ goto error;
+
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</fspoolstate>\n");
+
+ if (virBufferCheckError(&buf) < 0)
+ goto error;
+
+ if (!(xml = virBufferContentAndReset(&buf)))
+ goto error;
+
+ if (virFsPoolSaveXML(stateFile, def, xml))
+ goto error;
+
+ ret = 0;
+
+ error:
+ VIR_FREE(xml);
+ return ret;
+}
+
+
+int
+virFsPoolSaveConfig(const char *configFile,
+ virFsPoolDefPtr def)
+{
+ char *xml;
+ int ret = -1;
+
+ if (!(xml = virFsPoolDefFormat(def))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to generate XML"));
+ return -1;
+ }
+
+ if (virFsPoolSaveXML(configFile, def, xml))
+ goto cleanup;
+
+ ret = 0;
+ cleanup:
+ VIR_FREE(xml);
+ return ret;
+}
+
+int
+virFsPoolObjSaveDef(virFsDriverStatePtr driver,
+ virFsPoolObjPtr fspool,
+ virFsPoolDefPtr def)
+{
+ if (!fspool->configFile) {
+ if (virFileMakePath(driver->configDir) < 0) {
+ virReportSystemError(errno,
+ _("cannot create config directory %s"),
+ driver->configDir);
+ return -1;
+ }
+
+ if (!(fspool->configFile = virFileBuildPath(driver->configDir,
+ def->name, ".xml"))) {
+ return -1;
+ }
+
+ if (!(fspool->autostartLink = virFileBuildPath(driver->autostartDir,
+ def->name, ".xml"))) {
+ VIR_FREE(fspool->configFile);
+ return -1;
+ }
+ }
+
+ return virFsPoolSaveConfig(fspool->configFile, def);
+}
+
+int
+virFsPoolObjDeleteDef(virFsPoolObjPtr fspool)
+{
+ if (!fspool->configFile) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("no config file for %s"), fspool->def->name);
+ return -1;
+ }
+
+ if (unlink(fspool->configFile) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot remove config for %s"),
+ fspool->def->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+virFsPoolSourcePtr
+virFsPoolSourceListNewSource(virFsPoolSourceListPtr list)
+{
+ virFsPoolSourcePtr source;
+
+ if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0)
+ return NULL;
+
+ source = &list->sources[list->nsources++];
+ memset(source, 0, sizeof(*source));
+
+ return source;
+}
+
+char *
+virFsPoolSourceListFormat(virFsPoolSourceListPtr def)
+{
+ virFsPoolOptionsPtr options;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ const char *type;
+ size_t i;
+
+ options = virFsPoolOptionsForPoolType(def->type);
+ if (options == NULL)
+ return NULL;
+
+ type = virFsPoolTypeToString(def->type);
+ if (!type) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("unexpected fspool type"));
+ goto cleanup;
+ }
+
+ virBufferAddLit(&buf, "<sources>\n");
+ virBufferAdjustIndent(&buf, 2);
+
+ for (i = 0; i < def->nsources; i++)
+ virFsPoolSourceFormat(&buf, options, &def->sources[i]);
+
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</sources>\n");
+
+ if (virBufferCheckError(&buf) < 0)
+ goto cleanup;
+
+ return virBufferContentAndReset(&buf);
+
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ return NULL;
+}
+
+
+/*
+ * virFsPoolObjIsDuplicate:
+ * @doms : virFsPoolObjListPtr to search
+ * @def : virFsPoolDefPtr definition of fspool to lookup
+ * @check_active: If true, ensure that fspool is not active
+ *
+ * Returns: -1 on error
+ * 0 if fspool is new
+ * 1 if fspool is a duplicate
+ */
+int
+virFsPoolObjIsDuplicate(virFsPoolObjListPtr fspools,
+ virFsPoolDefPtr def,
+ unsigned int check_active)
+{
+ int ret = -1;
+ virFsPoolObjPtr fspool = NULL;
+
+ /* See if a Pool with matching UUID already exists */
+ fspool = virFsPoolObjFindByUUID(fspools, def->uuid);
+ if (fspool) {
+ /* UUID matches, but if names don't match, refuse it */
+ if (STRNEQ(fspool->def->name, def->name)) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(fspool->def->uuid, uuidstr);
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("fspool '%s' is already defined with uuid
%s"),
+ fspool->def->name, uuidstr);
+ goto cleanup;
+ }
+
+ if (check_active) {
+ /* UUID & name match, but if Pool is already active, refuse it */
+ if (virFsPoolObjIsActive(fspool)) {
+ virReportError(VIR_ERR_OPERATION_INVALID,
+ _("fspool is already active as '%s'"),
+ fspool->def->name);
+ goto cleanup;
+ }
+ }
+
+ ret = 1;
+ } else {
+ /* UUID does not match, but if a name matches, refuse it */
+ fspool = virFsPoolObjFindByName(fspools, def->name);
+ if (fspool) {
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virUUIDFormat(fspool->def->uuid, uuidstr);
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("fspool '%s' already exists with uuid
%s"),
+ def->name, uuidstr);
+ goto cleanup;
+ }
+ ret = 0;
+ }
+
+ cleanup:
+ if (fspool)
+ virFsPoolObjUnlock(fspool);
+ return ret;
+}
+
+int
+virFsPoolSourceFindDuplicate(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virFsPoolObjListPtr fspools,
+ virFsPoolDefPtr def)
+{
+ size_t i;
+ int ret = 1;
+ virFsPoolObjPtr fspool = NULL;
+ virFsPoolObjPtr matchfspool = NULL;
+
+ /* Check the fspool list for duplicate underlying storage */
+ for (i = 0; i < fspools->count; i++) {
+ fspool = fspools->objs[i];
+ if (def->type != fspool->def->type)
+ continue;
+
+ /* Don't mach against ourself if re-defining existing fspool ! */
+ if (STREQ(fspool->def->name, def->name))
+ continue;
+
+ virFsPoolObjLock(fspool);
+
+ switch ((virFsPoolType)fspool->def->type) {
+ case VIR_FS_POOL_DIR:
+ if (STREQ(fspool->def->target.path, def->target.path))
+ matchfspool = fspool;
+ break;
+
+ case VIR_FS_POOL_LAST:
+ break;
+ }
+ virFsPoolObjUnlock(fspool);
+
+ if (matchfspool)
+ break;
+ }
+
+ if (matchfspool) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Fs source conflict with fspool: '%s'"),
+ matchfspool->def->name);
+ ret = -1;
+ }
+ return ret;
+}
+
+void
+virFsPoolObjLock(virFsPoolObjPtr obj)
+{
+ virMutexLock(&obj->lock);
+}
+
+void
+virFsPoolObjUnlock(virFsPoolObjPtr obj)
+{
+ virMutexUnlock(&obj->lock);
+}
+
+#define MATCH(FLAG) (flags & (FLAG))
+static bool
+virFsPoolMatch(virFsPoolObjPtr fspoolobj,
+ unsigned int flags)
+{
+ /* filter by active state */
+ if (MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) &&
+ !((MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE) &&
+ virFsPoolObjIsActive(fspoolobj)) ||
+ (MATCH(VIR_CONNECT_LIST_FS_POOLS_INACTIVE) &&
+ !virFsPoolObjIsActive(fspoolobj))))
+ return false;
+
+ /* filter by persistence */
+ if (MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT) &&
+ !((MATCH(VIR_CONNECT_LIST_FS_POOLS_PERSISTENT) &&
+ fspoolobj->configFile) ||
+ (MATCH(VIR_CONNECT_LIST_FS_POOLS_TRANSIENT) &&
+ !fspoolobj->configFile)))
+ return false;
+
+ /* filter by autostart option */
+ if (MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART) &&
+ !((MATCH(VIR_CONNECT_LIST_FS_POOLS_AUTOSTART) &&
+ fspoolobj->autostart) ||
+ (MATCH(VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART) &&
+ !fspoolobj->autostart)))
+ return false;
+
+ /* filter by fspool type */
+ if (MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE)) {
+ if (!(MATCH(VIR_CONNECT_LIST_FS_POOLS_DIR) &&
+ (fspoolobj->def->type == VIR_FS_POOL_DIR)))
+ return false;
+ }
+
+ return true;
+}
+#undef MATCH
+
+int
+virFsPoolObjListExport(virConnectPtr conn,
+ virFsPoolObjList fspoolobjs,
+ virFsPoolPtr **fspools,
+ virFsPoolObjListFilter filter,
+ unsigned int flags)
+{
+ virFsPoolPtr *tmp_fspools = NULL;
+ virFsPoolPtr fspool = NULL;
+ int nfspools = 0;
+ int ret = -1;
+ size_t i;
+
+ if (fspools && VIR_ALLOC_N(tmp_fspools, fspoolobjs.count + 1) < 0)
+ goto cleanup;
+
+ for (i = 0; i < fspoolobjs.count; i++) {
+ virFsPoolObjPtr fspoolobj = fspoolobjs.objs[i];
+ virFsPoolObjLock(fspoolobj);
+ if ((!filter || filter(conn, fspoolobj->def)) &&
+ virFsPoolMatch(fspoolobj, flags)) {
+ if (fspools) {
+ if (!(fspool = virGetFsPool(conn,
+ fspoolobj->def->name,
+ fspoolobj->def->uuid,
+ NULL, NULL))) {
+ virFsPoolObjUnlock(fspoolobj);
+ goto cleanup;
+ }
+ tmp_fspools[nfspools] = fspool;
+ }
+ nfspools++;
+ }
+ virFsPoolObjUnlock(fspoolobj);
+ }
+
+ if (tmp_fspools) {
+ /* trim the array to the final size */
+ ignore_value(VIR_REALLOC_N(tmp_fspools, nfspools + 1));
+ *fspools = tmp_fspools;
+ tmp_fspools = NULL;
+ }
+
+ ret = nfspools;
+
+ cleanup:
+ if (tmp_fspools) {
+ for (i = 0; i < nfspools; i++)
+ virObjectUnref(tmp_fspools[i]);
+ }
+
+ VIR_FREE(tmp_fspools);
+ return ret;
+}
diff --git a/src/conf/fs_conf.h b/src/conf/fs_conf.h
new file mode 100644
index 0000000..fa8888a
--- /dev/null
+++ b/src/conf/fs_conf.h
@@ -0,0 +1,310 @@
+/*
+ * fs_conf.h: config handling for fs driver
+ *
+ */
+
+#ifndef __VIR_FS_CONF_H__
+# define __VIR_FS_CONF_H__
+
+# include "internal.h"
+# include "virbitmap.h"
+# include "virthread.h"
+# include "virutil.h"
+
+# include <libxml/tree.h>
+
+# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE \
+ VIR_CONNECT_LIST_FS_POOLS_DIR
+
+# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE \
+ (VIR_CONNECT_LIST_FS_POOLS_ACTIVE | \
+ VIR_CONNECT_LIST_FS_POOLS_INACTIVE)
+
+# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT \
+ (VIR_CONNECT_LIST_FS_POOLS_PERSISTENT | \
+ VIR_CONNECT_LIST_FS_POOLS_TRANSIENT)
+
+# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART \
+ (VIR_CONNECT_LIST_FS_POOLS_AUTOSTART | \
+ VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART)
+
+# define VIR_CONNECT_LIST_FS_POOLS_FILTERS_ALL \
+ (VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE | \
+ VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT | \
+ VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART | \
+ VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE)
+
+VIR_ENUM_DECL(virFsItem)
+VIR_ENUM_DECL(virFs)
+
+typedef struct _virFsPerms virFsPerms;
+typedef virFsPerms *virFsPermsPtr;
+struct _virFsPerms {
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ char *label;
+};
+
+typedef struct _virFsSourcePoolDef virFsSourcePoolDef;
+struct _virFsSourcePoolDef {
+ char *pool; /* pool name */
+ char *item; /* item name */
+ int itemtype; /* virFsItemType, internal only */
+ int pooltype; /* virFsPoolType internal only */
+};
+typedef virFsSourcePoolDef *virFsSourcePoolDefPtr;
+
+typedef struct _virFsSource virFsSource;
+typedef virFsSource *virFsSourcePtr;
+
+struct _virFsSource {
+ int type; /* virFsType */
+ char *path;
+ virFsSourcePoolDefPtr srcpool;
+ char *driverName;
+ virFsPermsPtr perms;
+ unsigned long long capacity; /* in bytes, 0 if unknown */
+ unsigned long long allocation; /* in bytes, 0 if unknown */
+};
+
+typedef enum {
+ VIR_FS_POOL_DIR, /* Local directory */
+ VIR_FS_POOL_LAST,
+} virFsPoolType;
+
+VIR_ENUM_DECL(virFsPool)
+
+typedef struct _virFsItemDef virFsItemDef;
+typedef virFsItemDef *virFsItemDefPtr;
+struct _virFsItemDef {
+ char *name;
+ char *key;
+ int type; /* virFsItemType */
+
+ bool building;
+ unsigned int in_use;
+
+ virFsSource target;
+};
+
+typedef struct _virFsItemDefList virFsItemDefList;
+typedef virFsItemDefList *virFsItemDefListPtr;
+struct _virFsItemDefList {
+ size_t count;
+ virFsItemDefPtr *objs;
+};
+
+typedef struct _virFsPoolSource virFsPoolSource;
+typedef virFsPoolSource *virFsPoolSourcePtr;
+struct _virFsPoolSource {
+ /* An optional (maybe multiple) host(s) */
+
+ /* Or a directory */
+ char *dir;
+
+ /* Or a name */
+ char *name;
+
+ /* Vendor of the source */
+ char *vendor;
+
+ /* Product name of the source*/
+ char *product;
+
+ /* Pool type specific format such as filesystem type,
+ * or lvm version, etc.
+ */
+ int format;
+};
+
+typedef struct _virFsPoolTarget virFsPoolTarget;
+typedef virFsPoolTarget *virFsPoolTargetPtr;
+struct _virFsPoolTarget {
+ char *path; /* Optional local filesystem mapping */
+ virFsPerms perms; /* Default permissions for volumes */
+};
+
+typedef struct _virFsPoolDef virFsPoolDef;
+typedef virFsPoolDef *virFsPoolDefPtr;
+struct _virFsPoolDef {
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ int type; /* virFsPoolType */
+
+ unsigned long long allocation; /* bytes */
+ unsigned long long capacity; /* bytes */
+ unsigned long long available; /* bytes */
+
+ virFsPoolSource source;
+ virFsPoolTarget target;
+};
+
+typedef struct _virFsPoolObj virFsPoolObj;
+typedef virFsPoolObj *virFsPoolObjPtr;
+
+struct _virFsPoolObj {
+ virMutex lock;
+
+ char *configFile;
+ char *autostartLink;
+ bool active;
+ int autostart;
+ unsigned int asyncjobs;
+
+ virFsPoolDefPtr def;
+ virFsPoolDefPtr newDef;
+
+ virFsItemDefList items;
+};
+
+typedef struct _virFsPoolObjList virFsPoolObjList;
+typedef virFsPoolObjList *virFsPoolObjListPtr;
+struct _virFsPoolObjList {
+ size_t count;
+ virFsPoolObjPtr *objs;
+};
+
+typedef struct _virFsDriverState virFsDriverState;
+typedef virFsDriverState *virFsDriverStatePtr;
+
+struct _virFsDriverState {
+ virMutex lock;
+
+ virFsPoolObjList fspools;
+
+ char *configDir;
+ char *autostartDir;
+ char *stateDir;
+ bool privileged;
+};
+
+typedef struct _virFsPoolSourceList virFsPoolSourceList;
+typedef virFsPoolSourceList *virFsPoolSourceListPtr;
+struct _virFsPoolSourceList {
+ int type;
+ unsigned int nsources;
+ virFsPoolSourcePtr sources;
+};
+
+typedef bool (*virFsPoolObjListFilter)(virConnectPtr conn,
+ virFsPoolDefPtr def);
+
+static inline int
+virFsPoolObjIsActive(virFsPoolObjPtr fspool)
+{
+ return fspool->active;
+}
+
+int virFsPoolLoadAllConfigs(virFsPoolObjListPtr fspools,
+ const char *configDir,
+ const char *autostartDir);
+
+int virFsPoolLoadAllState(virFsPoolObjListPtr fspools,
+ const char *stateDir);
+
+virFsPoolObjPtr
+virFsPoolLoadState(virFsPoolObjListPtr fspools,
+ const char *stateDir,
+ const char *name);
+virFsPoolObjPtr
+virFsPoolObjFindByUUID(virFsPoolObjListPtr fspools,
+ const unsigned char *uuid);
+virFsPoolObjPtr
+virFsPoolObjFindByName(virFsPoolObjListPtr fspools,
+ const char *name);
+
+virFsItemDefPtr
+virFsItemDefFindByKey(virFsPoolObjPtr fspool,
+ const char *key);
+virFsItemDefPtr
+virFsItemDefFindByPath(virFsPoolObjPtr fspool,
+ const char *path);
+virFsItemDefPtr
+virFsItemDefFindByName(virFsPoolObjPtr fspool,
+ const char *name);
+
+void virFsPoolObjClearItems(virFsPoolObjPtr fspool);
+
+virFsPoolDefPtr virFsPoolDefParseString(const char *xml);
+virFsPoolDefPtr virFsPoolDefParseFile(const char *filename);
+virFsPoolDefPtr virFsPoolDefParseNode(xmlDocPtr xml,
+ xmlNodePtr root);
+char *virFsPoolDefFormat(virFsPoolDefPtr def);
+
+typedef enum {
+ /* do not require volume capacity at all */
+ VIR_ITEM_XML_PARSE_NO_CAPACITY = 1 << 0,
+ /* do not require volume capacity if the volume has a backing store */
+ VIR_ITEM_XML_PARSE_OPT_CAPACITY = 1 << 1,
+} virFsItemDefParseFlags;
+
+virFsItemDefPtr
+virFsItemDefParseString(virFsPoolDefPtr fspool,
+ const char *xml,
+ unsigned int flags);
+virFsItemDefPtr
+virFsItemDefParseFile(virFsPoolDefPtr fspool,
+ const char *filename,
+ unsigned int flags);
+virFsItemDefPtr
+virFsItemDefParseNode(virFsPoolDefPtr fspool,
+ xmlDocPtr xml,
+ xmlNodePtr root,
+ unsigned int flags);
+char *virFsItemDefFormat(virFsPoolDefPtr fspool,
+ virFsItemDefPtr def);
+
+virFsPoolObjPtr
+virFsPoolObjAssignDef(virFsPoolObjListPtr fspools,
+ virFsPoolDefPtr def);
+
+int virFsPoolSaveState(const char *stateFile,
+ virFsPoolDefPtr def);
+int virFsPoolSaveConfig(const char *configFile,
+ virFsPoolDefPtr def);
+int virFsPoolObjSaveDef(virFsDriverStatePtr driver,
+ virFsPoolObjPtr fspool,
+ virFsPoolDefPtr def);
+int virFsPoolObjDeleteDef(virFsPoolObjPtr fspool);
+
+void virFsItemDefFree(virFsItemDefPtr def);
+void virFsPoolSourceClear(virFsPoolSourcePtr source);
+void virFsPoolSourceFree(virFsPoolSourcePtr source);
+void virFsPoolDefFree(virFsPoolDefPtr def);
+void virFsPoolObjFree(virFsPoolObjPtr fspool);
+void virFsPoolObjListFree(virFsPoolObjListPtr fspools);
+void virFsPoolObjRemove(virFsPoolObjListPtr fspools,
+ virFsPoolObjPtr fspool);
+
+virFsPoolSourcePtr
+virFsPoolDefParseSourceString(const char *srcSpec,
+ int fspool_type);
+virFsPoolSourcePtr
+virFsPoolSourceListNewSource(virFsPoolSourceListPtr list);
+char *virFsPoolSourceListFormat(virFsPoolSourceListPtr def);
+
+int virFsPoolObjIsDuplicate(virFsPoolObjListPtr fspools,
+ virFsPoolDefPtr def,
+ unsigned int check_active);
+
+char *virFsPoolGetVhbaSCSIHostParent(virConnectPtr conn,
+ const char *name)
+ ATTRIBUTE_NONNULL(1);
+
+int virFsPoolSourceFindDuplicate(virConnectPtr conn,
+ virFsPoolObjListPtr fspools,
+ virFsPoolDefPtr def);
+
+void virFsPoolObjLock(virFsPoolObjPtr obj);
+void virFsPoolObjUnlock(virFsPoolObjPtr obj);
+
+int virFsPoolObjListExport(virConnectPtr conn,
+ virFsPoolObjList fspoolobjs,
+ virFsPoolPtr **fspools,
+ virFsPoolObjListFilter filter,
+ unsigned int flags);
+
+
+
+#endif /* __VIR_FS_CONF_H__ */
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 2efaab1..026543c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -565,6 +565,48 @@ virDomainConfNWFilterTeardown;
virDomainConfVMNWFilterTeardown;
+# conf/fs_conf.h
+virFsItemDefFindByKey;
+virFsItemDefFindByName;
+virFsItemDefFindByPath;
+virFsItemDefFormat;
+virFsItemDefFree;
+virFsItemDefParseFile;
+virFsItemDefParseNode;
+virFsItemDefParseString;
+virFsItemTypeFromString;
+virFsItemTypeToString;
+virFsPoolDefFormat;
+virFsPoolDefFree;
+virFsPoolDefParseFile;
+virFsPoolDefParseNode;
+virFsPoolDefParseSourceString;
+virFsPoolDefParseString;
+virFsPoolLoadAllConfigs;
+virFsPoolLoadAllState;
+virFsPoolObjAssignDef;
+virFsPoolObjClearItems;
+virFsPoolObjDeleteDef;
+virFsPoolObjFindByName;
+virFsPoolObjFindByUUID;
+virFsPoolObjIsDuplicate;
+virFsPoolObjListExport;
+virFsPoolObjListFree;
+virFsPoolObjLock;
+virFsPoolObjRemove;
+virFsPoolObjSaveDef;
+virFsPoolObjUnlock;
+virFsPoolSaveConfig;
+virFsPoolSaveState;
+virFsPoolSourceClear;
+virFsPoolSourceFindDuplicate;
+virFsPoolSourceFree;
+virFsPoolSourceListFormat;
+virFsPoolSourceListNewSource;
+virFsPoolTypeFromString;
+virFsPoolTypeToString;
+
+
# conf/interface_conf.h
virInterfaceAssignDef;
virInterfaceDefFormat;
--
1.8.3.1