From: Olga Krishtal <okrishtal@xxxxxxxxxxxxx> Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@xxxxxxxxxxxxx> --- 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 6c04343..313edf2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -23,6 +23,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 f963345..77e64f4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -394,6 +394,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) \ @@ -405,6 +409,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 c59f02a..9c3fe6a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -553,6 +553,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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list