libvirt/src/conf/storage_conf.c
Matthias Bolte 1573158190 Remove PATH_MAX sized stack allocations related to virFileBuildPath
Make virFileBuildPath operate on the heap instead of the stack. It
allocates a buffer instead of expecting a preexisting buffer.
2011-04-05 08:55:27 +02:00

1728 lines
50 KiB
C

/*
* storage_conf.c: config handling for storage driver
*
* Copyright (C) 2006-2010 Red Hat, Inc.
* Copyright (C) 2006-2008 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#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 "virterror_internal.h"
#include "datatypes.h"
#include "storage_conf.h"
#include "storage_file.h"
#include "xml.h"
#include "uuid.h"
#include "buf.h"
#include "util.h"
#include "memory.h"
#include "files.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
VIR_ENUM_IMPL(virStoragePool,
VIR_STORAGE_POOL_LAST,
"dir", "fs", "netfs",
"logical", "disk", "iscsi",
"scsi", "mpath")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
VIR_STORAGE_POOL_FS_LAST,
"auto", "ext2", "ext3",
"ext4", "ufs", "iso9660", "udf",
"gfs", "gfs2", "vfat", "hfs+", "xfs", "ocfs2")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
VIR_STORAGE_POOL_NETFS_LAST,
"auto", "nfs", "glusterfs", "cifs")
VIR_ENUM_IMPL(virStoragePoolFormatDisk,
VIR_STORAGE_POOL_DISK_LAST,
"unknown", "dos", "dvh", "gpt",
"mac", "bsd", "pc98", "sun", "lvm2")
VIR_ENUM_IMPL(virStoragePoolFormatLogical,
VIR_STORAGE_POOL_LOGICAL_LAST,
"unknown", "lvm2")
VIR_ENUM_IMPL(virStorageVolFormatDisk,
VIR_STORAGE_VOL_DISK_LAST,
"none", "linux", "fat16",
"fat32", "linux-swap",
"linux-lvm", "linux-raid",
"extended")
VIR_ENUM_IMPL(virStoragePartedFsType,
VIR_STORAGE_PARTED_FS_TYPE_LAST,
"ext2", "ext2", "fat16",
"fat32", "linux-swap",
"ext2", "ext2",
"extended")
typedef const char *(*virStorageVolFormatToString)(int format);
typedef int (*virStorageVolFormatFromString)(const char *format);
typedef const char *(*virStoragePoolFormatToString)(int format);
typedef int (*virStoragePoolFormatFromString)(const char *format);
typedef struct _virStorageVolOptions virStorageVolOptions;
typedef virStorageVolOptions *virStorageVolOptionsPtr;
struct _virStorageVolOptions {
int defaultFormat;
virStorageVolFormatToString formatToString;
virStorageVolFormatFromString formatFromString;
};
/* Flags to indicate mandatory components in the pool source */
enum {
VIR_STORAGE_POOL_SOURCE_HOST = (1<<0),
VIR_STORAGE_POOL_SOURCE_DEVICE = (1<<1),
VIR_STORAGE_POOL_SOURCE_DIR = (1<<2),
VIR_STORAGE_POOL_SOURCE_ADAPTER = (1<<3),
VIR_STORAGE_POOL_SOURCE_NAME = (1<<4),
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN = (1<<5),
};
typedef struct _virStoragePoolOptions virStoragePoolOptions;
typedef virStoragePoolOptions *virStoragePoolOptionsPtr;
struct _virStoragePoolOptions {
int flags;
int defaultFormat;
virStoragePoolFormatToString formatToString;
virStoragePoolFormatFromString formatFromString;
};
typedef struct _virStoragePoolTypeInfo virStoragePoolTypeInfo;
typedef virStoragePoolTypeInfo *virStoragePoolTypeInfoPtr;
struct _virStoragePoolTypeInfo {
int poolType;
virStoragePoolOptions poolOptions;
virStorageVolOptions volOptions;
};
static virStoragePoolTypeInfo poolTypeInfo[] = {
{ .poolType = VIR_STORAGE_POOL_LOGICAL,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_NAME |
VIR_STORAGE_POOL_SOURCE_DEVICE),
.defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2,
.formatFromString = virStoragePoolFormatLogicalTypeFromString,
.formatToString = virStoragePoolFormatLogicalTypeToString,
},
},
{ .poolType = VIR_STORAGE_POOL_DIR,
.volOptions = {
.defaultFormat = VIR_STORAGE_FILE_RAW,
.formatFromString = virStorageFileFormatTypeFromString,
.formatToString = virStorageFileFormatTypeToString,
},
},
{ .poolType = VIR_STORAGE_POOL_FS,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
.defaultFormat = VIR_STORAGE_POOL_FS_AUTO,
.formatFromString = virStoragePoolFormatFileSystemTypeFromString,
.formatToString = virStoragePoolFormatFileSystemTypeToString,
},
.volOptions = {
.defaultFormat = VIR_STORAGE_FILE_RAW,
.formatFromString = virStorageFileFormatTypeFromString,
.formatToString = virStorageFileFormatTypeToString,
},
},
{ .poolType = VIR_STORAGE_POOL_NETFS,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
VIR_STORAGE_POOL_SOURCE_DIR),
.defaultFormat = VIR_STORAGE_POOL_NETFS_AUTO,
.formatFromString = virStoragePoolFormatFileSystemNetTypeFromString,
.formatToString = virStoragePoolFormatFileSystemNetTypeToString,
},
.volOptions = {
.defaultFormat = VIR_STORAGE_FILE_RAW,
.formatFromString = virStorageFileFormatTypeFromString,
.formatToString = virStorageFileFormatTypeToString,
},
},
{ .poolType = VIR_STORAGE_POOL_ISCSI,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
VIR_STORAGE_POOL_SOURCE_DEVICE |
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
},
.volOptions = {
.formatToString = virStoragePoolFormatDiskTypeToString,
}
},
{ .poolType = VIR_STORAGE_POOL_SCSI,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER),
},
.volOptions = {
.formatToString = virStoragePoolFormatDiskTypeToString,
}
},
{ .poolType = VIR_STORAGE_POOL_MPATH,
.volOptions = {
.formatToString = virStoragePoolFormatDiskTypeToString,
}
},
{ .poolType = VIR_STORAGE_POOL_DISK,
.poolOptions = {
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
.defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN,
.formatFromString = virStoragePoolFormatDiskTypeFromString,
.formatToString = virStoragePoolFormatDiskTypeToString,
},
.volOptions = {
.defaultFormat = VIR_STORAGE_VOL_DISK_NONE,
.formatFromString = virStorageVolFormatDiskTypeFromString,
.formatToString = virStorageVolFormatDiskTypeToString,
},
}
};
static virStoragePoolTypeInfoPtr
virStoragePoolTypeInfoLookup(int type) {
unsigned int i;
for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo) ; i++)
if (poolTypeInfo[i].poolType == type)
return &poolTypeInfo[i];
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("missing backend for pool type %d"), type);
return NULL;
}
static virStoragePoolOptionsPtr
virStoragePoolOptionsForPoolType(int type) {
virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
if (backend == NULL)
return NULL;
return &backend->poolOptions;
}
static virStorageVolOptionsPtr
virStorageVolOptionsForPoolType(int type) {
virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
if (backend == NULL)
return NULL;
return &backend->volOptions;
}
void
virStorageVolDefFree(virStorageVolDefPtr def) {
int i;
if (!def)
return;
VIR_FREE(def->name);
VIR_FREE(def->key);
for (i = 0 ; i < def->source.nextent ; i++) {
VIR_FREE(def->source.extents[i].path);
}
VIR_FREE(def->source.extents);
VIR_FREE(def->target.path);
VIR_FREE(def->target.perms.label);
virStorageEncryptionFree(def->target.encryption);
VIR_FREE(def->backingStore.path);
VIR_FREE(def->backingStore.perms.label);
virStorageEncryptionFree(def->backingStore.encryption);
VIR_FREE(def);
}
void
virStoragePoolSourceFree(virStoragePoolSourcePtr source) {
int i;
if (!source)
return;
VIR_FREE(source->host.name);
for (i = 0 ; i < source->ndevice ; i++) {
VIR_FREE(source->devices[i].freeExtents);
VIR_FREE(source->devices[i].path);
}
VIR_FREE(source->devices);
VIR_FREE(source->dir);
VIR_FREE(source->name);
VIR_FREE(source->adapter);
VIR_FREE(source->initiator.iqn);
VIR_FREE(source->vendor);
VIR_FREE(source->product);
if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
VIR_FREE(source->auth.chap.login);
VIR_FREE(source->auth.chap.passwd);
}
}
void
virStoragePoolDefFree(virStoragePoolDefPtr def) {
if (!def)
return;
VIR_FREE(def->name);
virStoragePoolSourceFree(&def->source);
VIR_FREE(def->target.path);
VIR_FREE(def->target.perms.label);
VIR_FREE(def);
}
void
virStoragePoolObjFree(virStoragePoolObjPtr obj) {
if (!obj)
return;
virStoragePoolObjClearVols(obj);
virStoragePoolDefFree(obj->def);
virStoragePoolDefFree(obj->newDef);
VIR_FREE(obj->configFile);
VIR_FREE(obj->autostartLink);
virMutexDestroy(&obj->lock);
VIR_FREE(obj);
}
void virStoragePoolObjListFree(virStoragePoolObjListPtr pools)
{
unsigned int i;
for (i = 0 ; i < pools->count ; i++)
virStoragePoolObjFree(pools->objs[i]);
VIR_FREE(pools->objs);
pools->count = 0;
}
void
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
virStoragePoolObjPtr pool)
{
unsigned int i;
virStoragePoolObjUnlock(pool);
for (i = 0 ; i < pools->count ; i++) {
virStoragePoolObjLock(pools->objs[i]);
if (pools->objs[i] == pool) {
virStoragePoolObjUnlock(pools->objs[i]);
virStoragePoolObjFree(pools->objs[i]);
if (i < (pools->count - 1))
memmove(pools->objs + i, pools->objs + i + 1,
sizeof(*(pools->objs)) * (pools->count - (i + 1)));
if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
; /* Failure to reduce memory allocation isn't fatal */
}
pools->count--;
break;
}
virStoragePoolObjUnlock(pools->objs[i]);
}
}
static int
virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
virStoragePoolAuthChapPtr auth) {
auth->login = virXPathString("string(./auth/@login)", ctxt);
if (auth->login == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing auth host attribute"));
return -1;
}
auth->passwd = virXPathString("string(./auth/@passwd)", ctxt);
if (auth->passwd == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing auth passwd attribute"));
return -1;
}
return 0;
}
static int
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
virStoragePoolSourcePtr source,
int pool_type,
xmlNodePtr node) {
int ret = -1;
xmlNodePtr relnode, *nodeset = NULL;
char *authType = NULL;
int nsource, i;
virStoragePoolOptionsPtr options;
char *port = NULL;
relnode = ctxt->node;
ctxt->node = node;
if ((options = virStoragePoolOptionsForPoolType(pool_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) {
virStorageReportError(VIR_ERR_XML_ERROR,
_("unknown pool format type %s"), format);
VIR_FREE(format);
goto cleanup;
}
VIR_FREE(format);
}
source->host.name = virXPathString("string(./host/@name)", ctxt);
port = virXPathString("string(./host/@port)", ctxt);
if (port) {
if (virStrToLong_i(port, NULL, 10, &source->host.port) < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
_("Invalid port number: %s"),
port);
goto cleanup;
}
}
source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
nsource = virXPathNodeSet("./device", ctxt, &nodeset);
if (nsource > 0) {
if (VIR_ALLOC_N(source->devices, nsource) < 0) {
VIR_FREE(nodeset);
virReportOOMError();
goto cleanup;
}
for (i = 0 ; i < nsource ; i++) {
char *path = virXMLPropString(nodeset[i], "path");
if (path == NULL) {
VIR_FREE(nodeset);
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing storage pool source device path"));
goto cleanup;
}
source->devices[i].path = path;
}
source->ndevice = nsource;
}
source->dir = virXPathString("string(./dir/@path)", ctxt);
source->adapter = virXPathString("string(./adapter/@name)", ctxt);
authType = virXPathString("string(./auth/@type)", ctxt);
if (authType == NULL) {
source->authType = VIR_STORAGE_POOL_AUTH_NONE;
} else {
if (STREQ(authType, "chap")) {
source->authType = VIR_STORAGE_POOL_AUTH_CHAP;
} else {
virStorageReportError(VIR_ERR_XML_ERROR,
_("unknown auth type '%s'"),
(const char *)authType);
goto cleanup;
}
}
if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
if (virStoragePoolDefParseAuthChap(ctxt, &source->auth.chap) < 0)
goto cleanup;
}
source->vendor = virXPathString("string(./vendor/@name)", ctxt);
source->product = virXPathString("string(./product/@name)", ctxt);
ret = 0;
cleanup:
ctxt->node = relnode;
VIR_FREE(port);
VIR_FREE(authType);
VIR_FREE(nodeset);
return ret;
}
virStoragePoolSourcePtr
virStoragePoolDefParseSourceString(const char *srcSpec,
int pool_type)
{
xmlDocPtr doc = NULL;
xmlNodePtr node = NULL;
xmlXPathContextPtr xpath_ctxt = NULL;
virStoragePoolSourcePtr def = NULL, ret = NULL;
doc = xmlReadDoc((const xmlChar *)srcSpec, "srcSpec.xml", NULL,
XML_PARSE_NOENT | XML_PARSE_NONET |
XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
if (doc == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("bad <source> spec"));
goto cleanup;
}
xpath_ctxt = xmlXPathNewContext(doc);
if (xpath_ctxt == NULL) {
virReportOOMError();
goto cleanup;
}
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
goto cleanup;
}
node = virXPathNode("/source", xpath_ctxt);
if (!node) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("root element was not source"));
goto cleanup;
}
if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
node) < 0)
goto cleanup;
ret = def;
def = NULL;
cleanup:
virStoragePoolSourceFree(def);
VIR_FREE(def);
xmlFreeDoc(doc);
xmlXPathFreeContext(xpath_ctxt);
return ret;
}
static int
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
virStoragePermsPtr perms,
const char *permxpath,
int defaultmode) {
char *mode;
long v;
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 = defaultmode;
perms->uid = -1;
perms->gid = -1;
perms->label = NULL;
return 0;
}
relnode = ctxt->node;
ctxt->node = node;
mode = virXPathString("string(./mode)", ctxt);
if (!mode) {
perms->mode = defaultmode;
} else {
char *end = NULL;
perms->mode = strtol(mode, &end, 8);
if (*end || perms->mode < 0 || perms->mode > 0777) {
VIR_FREE(mode);
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("malformed octal mode"));
goto error;
}
VIR_FREE(mode);
}
if (virXPathNode("./owner", ctxt) == NULL) {
perms->uid = -1;
} else {
if (virXPathLong("number(./owner)", ctxt, &v) < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("malformed owner element"));
goto error;
}
perms->uid = (int)v;
}
if (virXPathNode("./group", ctxt) == NULL) {
perms->gid = -1;
} else {
if (virXPathLong("number(./group)", ctxt, &v) < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("malformed group element"));
goto error;
}
perms->gid = (int)v;
}
/* 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 virStoragePoolDefPtr
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
virStoragePoolOptionsPtr options;
virStoragePoolDefPtr ret;
xmlNodePtr source_node;
char *type = NULL;
char *uuid = NULL;
char *tmppath;
if (VIR_ALLOC(ret) < 0) {
virReportOOMError();
return NULL;
}
type = virXPathString("string(./@type)", ctxt);
if ((ret->type = virStoragePoolTypeFromString((const char *)type)) < 0) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown storage pool type %s"), (const char*)type);
goto cleanup;
}
xmlFree(type);
type = NULL;
if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) {
goto cleanup;
}
source_node = virXPathNode("./source", ctxt);
if (source_node) {
if (virStoragePoolDefParseSource(ctxt, &ret->source, ret->type,
source_node) < 0)
goto cleanup;
}
ret->name = virXPathString("string(./name)", ctxt);
if (ret->name == NULL &&
options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
ret->name = ret->source.name;
if (ret->name == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing pool source name element"));
goto cleanup;
}
uuid = virXPathString("string(./uuid)", ctxt);
if (uuid == NULL) {
if (virUUIDGenerate(ret->uuid) < 0) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unable to generate uuid"));
goto cleanup;
}
} else {
if (virUUIDParse(uuid, ret->uuid) < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("malformed uuid element"));
goto cleanup;
}
VIR_FREE(uuid);
}
if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
if (!ret->source.host.name) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s",
_("missing storage pool source host name"));
goto cleanup;
}
}
if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
if (!ret->source.dir) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing storage pool source path"));
goto cleanup;
}
}
if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
if (ret->source.name == NULL) {
/* source name defaults to pool name */
ret->source.name = strdup(ret->name);
if (ret->source.name == NULL) {
virReportOOMError();
goto cleanup;
}
}
}
if (options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) {
if (!ret->source.adapter) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing storage pool source adapter name"));
goto cleanup;
}
}
/* If DEVICE is the only source type, then its required */
if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
if (!ret->source.ndevice) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing storage pool source device name"));
goto cleanup;
}
}
if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing storage pool target path"));
goto cleanup;
}
ret->target.path = virFileSanitizePath(tmppath);
VIR_FREE(tmppath);
if (!ret->target.path)
goto cleanup;
if (virStorageDefParsePerms(ctxt, &ret->target.perms,
"./target/permissions", 0700) < 0)
goto cleanup;
return ret;
cleanup:
VIR_FREE(uuid);
xmlFree(type);
virStoragePoolDefFree(ret);
return NULL;
}
virStoragePoolDefPtr
virStoragePoolDefParseNode(xmlDocPtr xml,
xmlNodePtr root) {
xmlXPathContextPtr ctxt = NULL;
virStoragePoolDefPtr def = NULL;
if (STRNEQ((const char *)root->name, "pool")) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("unknown root element for storage pool"));
goto cleanup;
}
ctxt = xmlXPathNewContext(xml);
if (ctxt == NULL) {
virReportOOMError();
goto cleanup;
}
ctxt->node = root;
def = virStoragePoolDefParseXML(ctxt);
cleanup:
xmlXPathFreeContext(ctxt);
return def;
}
static virStoragePoolDefPtr
virStoragePoolDefParse(const char *xmlStr,
const char *filename) {
virStoragePoolDefPtr ret = NULL;
xmlDocPtr xml;
if ((xml = virXMLParse(filename, xmlStr, "storage.xml"))) {
ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
return ret;
}
virStoragePoolDefPtr
virStoragePoolDefParseString(const char *xmlStr)
{
return virStoragePoolDefParse(xmlStr, NULL);
}
virStoragePoolDefPtr
virStoragePoolDefParseFile(const char *filename)
{
return virStoragePoolDefParse(NULL, filename);
}
static int
virStoragePoolSourceFormat(virBufferPtr buf,
virStoragePoolOptionsPtr options,
virStoragePoolSourcePtr src)
{
int i, j;
virBufferAddLit(buf," <source>\n");
if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) &&
src->host.name) {
virBufferVSprintf(buf, " <host name='%s'", src->host.name);
if (src->host.port)
virBufferVSprintf(buf, " port='%d'", src->host.port);
virBufferAddLit(buf, "/>\n");
}
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
src->ndevice) {
for (i = 0 ; i < src->ndevice ; i++) {
if (src->devices[i].nfreeExtent) {
virBufferVSprintf(buf," <device path='%s'>\n",
src->devices[i].path);
for (j = 0 ; j < src->devices[i].nfreeExtent ; j++) {
virBufferVSprintf(buf, " <freeExtent start='%llu' end='%llu'/>\n",
src->devices[i].freeExtents[j].start,
src->devices[i].freeExtents[j].end);
}
virBufferAddLit(buf," </device>\n");
}
else
virBufferVSprintf(buf, " <device path='%s'/>\n",
src->devices[i].path);
}
}
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) &&
src->dir)
virBufferVSprintf(buf," <dir path='%s'/>\n", src->dir);
if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) &&
src->adapter)
virBufferVSprintf(buf," <adapter name='%s'/>\n", src->adapter);
if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) &&
src->name)
virBufferVSprintf(buf," <name>%s</name>\n", src->name);
if ((options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN) &&
src->initiator.iqn) {
virBufferAddLit(buf," <initiator>\n");
virBufferEscapeString(buf," <iqn name='%s'/>\n", src->initiator.iqn);
virBufferAddLit(buf," </initiator>\n");
}
if (options->formatToString) {
const char *format = (options->formatToString)(src->format);
if (!format) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown pool format number %d"),
src->format);
return -1;
}
virBufferVSprintf(buf," <format type='%s'/>\n", format);
}
if (src->authType == VIR_STORAGE_POOL_AUTH_CHAP)
virBufferVSprintf(buf," <auth type='chap' login='%s' passwd='%s'/>\n",
src->auth.chap.login,
src->auth.chap.passwd);
if (src->vendor != NULL) {
virBufferEscapeString(buf," <vendor name='%s'/>\n", src->vendor);
}
if (src->product != NULL) {
virBufferEscapeString(buf," <product name='%s'/>\n", src->product);
}
virBufferAddLit(buf," </source>\n");
return 0;
}
char *
virStoragePoolDefFormat(virStoragePoolDefPtr def) {
virStoragePoolOptionsPtr options;
virBuffer buf = VIR_BUFFER_INITIALIZER;
const char *type;
char uuid[VIR_UUID_STRING_BUFLEN];
options = virStoragePoolOptionsForPoolType(def->type);
if (options == NULL)
return NULL;
type = virStoragePoolTypeToString(def->type);
if (!type) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unexpected pool type"));
goto cleanup;
}
virBufferVSprintf(&buf, "<pool type='%s'>\n", type);
virBufferVSprintf(&buf," <name>%s</name>\n", def->name);
virUUIDFormat(def->uuid, uuid);
virBufferVSprintf(&buf," <uuid>%s</uuid>\n", uuid);
virBufferVSprintf(&buf," <capacity>%llu</capacity>\n",
def->capacity);
virBufferVSprintf(&buf," <allocation>%llu</allocation>\n",
def->allocation);
virBufferVSprintf(&buf," <available>%llu</available>\n",
def->available);
if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0)
goto cleanup;
virBufferAddLit(&buf," <target>\n");
if (def->target.path)
virBufferVSprintf(&buf," <path>%s</path>\n", def->target.path);
virBufferAddLit(&buf," <permissions>\n");
virBufferVSprintf(&buf," <mode>0%o</mode>\n",
def->target.perms.mode);
virBufferVSprintf(&buf," <owner>%d</owner>\n",
def->target.perms.uid);
virBufferVSprintf(&buf," <group>%d</group>\n",
def->target.perms.gid);
if (def->target.perms.label)
virBufferVSprintf(&buf," <label>%s</label>\n",
def->target.perms.label);
virBufferAddLit(&buf," </permissions>\n");
virBufferAddLit(&buf," </target>\n");
virBufferAddLit(&buf,"</pool>\n");
if (virBufferError(&buf))
goto no_memory;
return virBufferContentAndReset(&buf);
no_memory:
virReportOOMError();
cleanup:
virBufferFreeAndReset(&buf);
return NULL;
}
static int
virStorageSize(const char *unit,
const char *val,
unsigned long long *ret) {
unsigned long long mult;
char *end;
if (!unit) {
mult = 1;
} else {
switch (unit[0]) {
case 'k':
case 'K':
mult = 1024ull;
break;
case 'm':
case 'M':
mult = 1024ull * 1024ull;
break;
case 'g':
case 'G':
mult = 1024ull * 1024ull * 1024ull;
break;
case 't':
case 'T':
mult = 1024ull * 1024ull * 1024ull * 1024ull;
break;
case 'p':
case 'P':
mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull;
break;
case 'e':
case 'E':
mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull *
1024ull;
break;
default:
virStorageReportError(VIR_ERR_XML_ERROR,
_("unknown size units '%s'"), unit);
return -1;
}
}
if (virStrToLong_ull (val, &end, 10, ret) < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("malformed capacity element"));
return -1;
}
if (*ret > (ULLONG_MAX / mult)) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("capacity element value too large"));
return -1;
}
*ret *= mult;
return 0;
}
static virStorageVolDefPtr
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
xmlXPathContextPtr ctxt) {
virStorageVolDefPtr ret;
virStorageVolOptionsPtr options;
char *allocation = NULL;
char *capacity = NULL;
char *unit = NULL;
xmlNodePtr node;
options = virStorageVolOptionsForPoolType(pool->type);
if (options == NULL)
return NULL;
if (VIR_ALLOC(ret) < 0) {
virReportOOMError();
return NULL;
}
ret->name = virXPathString("string(./name)", ctxt);
if (ret->name == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing volume name element"));
goto cleanup;
}
/* Auto-generated so deliberately ignore */
/*ret->key = virXPathString("string(./key)", ctxt);*/
capacity = virXPathString("string(./capacity)", ctxt);
unit = virXPathString("string(./capacity/@unit)", ctxt);
if (capacity == NULL) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("missing capacity element"));
goto cleanup;
}
if (virStorageSize(unit, capacity, &ret->capacity) < 0)
goto cleanup;
VIR_FREE(capacity);
VIR_FREE(unit);
allocation = virXPathString("string(./allocation)", ctxt);
if (allocation) {
unit = virXPathString("string(./allocation/@unit)", ctxt);
if (virStorageSize(unit, allocation, &ret->allocation) < 0)
goto cleanup;
VIR_FREE(allocation);
VIR_FREE(unit);
} else {
ret->allocation = ret->capacity;
}
ret->target.path = virXPathString("string(./target/path)", ctxt);
if (options->formatFromString) {
char *format = virXPathString("string(./target/format/@type)", ctxt);
if (format == NULL)
ret->target.format = options->defaultFormat;
else
ret->target.format = (options->formatFromString)(format);
if (ret->target.format < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
_("unknown volume format type %s"), format);
VIR_FREE(format);
goto cleanup;
}
VIR_FREE(format);
}
if (virStorageDefParsePerms(ctxt, &ret->target.perms,
"./target/permissions", 0600) < 0)
goto cleanup;
node = virXPathNode("./target/encryption", ctxt);
if (node != NULL) {
ret->target.encryption = virStorageEncryptionParseNode(ctxt->doc,
node);
if (ret->target.encryption == NULL)
goto cleanup;
}
ret->backingStore.path = virXPathString("string(./backingStore/path)", ctxt);
if (options->formatFromString) {
char *format = virXPathString("string(./backingStore/format/@type)", ctxt);
if (format == NULL)
ret->backingStore.format = options->defaultFormat;
else
ret->backingStore.format = (options->formatFromString)(format);
if (ret->backingStore.format < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
_("unknown volume format type %s"), format);
VIR_FREE(format);
goto cleanup;
}
VIR_FREE(format);
}
if (virStorageDefParsePerms(ctxt, &ret->backingStore.perms,
"./backingStore/permissions", 0600) < 0)
goto cleanup;
return ret;
cleanup:
VIR_FREE(allocation);
VIR_FREE(capacity);
VIR_FREE(unit);
virStorageVolDefFree(ret);
return NULL;
}
virStorageVolDefPtr
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
xmlDocPtr xml,
xmlNodePtr root) {
xmlXPathContextPtr ctxt = NULL;
virStorageVolDefPtr def = NULL;
if (STRNEQ((const char *)root->name, "volume")) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("unknown root element for storage vol"));
goto cleanup;
}
ctxt = xmlXPathNewContext(xml);
if (ctxt == NULL) {
virReportOOMError();
goto cleanup;
}
ctxt->node = root;
def = virStorageVolDefParseXML(pool, ctxt);
cleanup:
xmlXPathFreeContext(ctxt);
return def;
}
static virStorageVolDefPtr
virStorageVolDefParse(virStoragePoolDefPtr pool,
const char *xmlStr,
const char *filename) {
virStorageVolDefPtr ret = NULL;
xmlDocPtr xml;
if ((xml = virXMLParse(filename, xmlStr, "storage.xml"))) {
ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml));
xmlFreeDoc(xml);
}
return ret;
}
virStorageVolDefPtr
virStorageVolDefParseString(virStoragePoolDefPtr pool,
const char *xmlStr)
{
return virStorageVolDefParse(pool, xmlStr, NULL);
}
virStorageVolDefPtr
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
const char *filename)
{
return virStorageVolDefParse(pool, NULL, filename);
}
static int
virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
virBufferPtr buf,
virStorageVolTargetPtr def,
const char *type) {
virBufferVSprintf(buf, " <%s>\n", type);
if (def->path)
virBufferVSprintf(buf," <path>%s</path>\n", def->path);
if (options->formatToString) {
const char *format = (options->formatToString)(def->format);
if (!format) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("unknown volume format number %d"),
def->format);
return -1;
}
virBufferVSprintf(buf," <format type='%s'/>\n", format);
}
virBufferAddLit(buf," <permissions>\n");
virBufferVSprintf(buf," <mode>0%o</mode>\n",
def->perms.mode);
virBufferVSprintf(buf," <owner>%d</owner>\n",
def->perms.uid);
virBufferVSprintf(buf," <group>%d</group>\n",
def->perms.gid);
if (def->perms.label)
virBufferVSprintf(buf," <label>%s</label>\n",
def->perms.label);
virBufferAddLit(buf," </permissions>\n");
if (def->encryption != NULL &&
virStorageEncryptionFormat(buf, def->encryption, 4) < 0)
return -1;
virBufferVSprintf(buf, " </%s>\n", type);
return 0;
}
char *
virStorageVolDefFormat(virStoragePoolDefPtr pool,
virStorageVolDefPtr def) {
virStorageVolOptionsPtr options;
virBuffer buf = VIR_BUFFER_INITIALIZER;
options = virStorageVolOptionsForPoolType(pool->type);
if (options == NULL)
return NULL;
virBufferAddLit(&buf, "<volume>\n");
virBufferVSprintf(&buf," <name>%s</name>\n", def->name);
virBufferVSprintf(&buf," <key>%s</key>\n", def->key);
virBufferAddLit(&buf, " <source>\n");
if (def->source.nextent) {
int i;
const char *thispath = NULL;
for (i = 0 ; i < def->source.nextent ; i++) {
if (thispath == NULL ||
STRNEQ(thispath, def->source.extents[i].path)) {
if (thispath != NULL)
virBufferAddLit(&buf, " </device>\n");
virBufferVSprintf(&buf, " <device path='%s'>\n",
def->source.extents[i].path);
}
virBufferVSprintf(&buf,
" <extent start='%llu' end='%llu'/>\n",
def->source.extents[i].start,
def->source.extents[i].end);
thispath = def->source.extents[i].path;
}
if (thispath != NULL)
virBufferAddLit(&buf, " </device>\n");
}
virBufferAddLit(&buf, " </source>\n");
virBufferVSprintf(&buf," <capacity>%llu</capacity>\n",
def->capacity);
virBufferVSprintf(&buf," <allocation>%llu</allocation>\n",
def->allocation);
if (virStorageVolTargetDefFormat(options, &buf,
&def->target, "target") < 0)
goto cleanup;
if (def->backingStore.path &&
virStorageVolTargetDefFormat(options, &buf,
&def->backingStore, "backingStore") < 0)
goto cleanup;
virBufferAddLit(&buf,"</volume>\n");
if (virBufferError(&buf))
goto no_memory;
return virBufferContentAndReset(&buf);
no_memory:
virReportOOMError();
cleanup:
virBufferFreeAndReset(&buf);
return NULL;
}
virStoragePoolObjPtr
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
const unsigned char *uuid) {
unsigned int i;
for (i = 0 ; i < pools->count ; i++) {
virStoragePoolObjLock(pools->objs[i]);
if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
return pools->objs[i];
virStoragePoolObjUnlock(pools->objs[i]);
}
return NULL;
}
virStoragePoolObjPtr
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
const char *name) {
unsigned int i;
for (i = 0 ; i < pools->count ; i++) {
virStoragePoolObjLock(pools->objs[i]);
if (STREQ(pools->objs[i]->def->name, name))
return pools->objs[i];
virStoragePoolObjUnlock(pools->objs[i]);
}
return NULL;
}
void
virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
{
unsigned int i;
for (i = 0 ; i < pool->volumes.count ; i++)
virStorageVolDefFree(pool->volumes.objs[i]);
VIR_FREE(pool->volumes.objs);
pool->volumes.count = 0;
}
virStorageVolDefPtr
virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
const char *key) {
unsigned int i;
for (i = 0 ; i < pool->volumes.count ; i++)
if (STREQ(pool->volumes.objs[i]->key, key))
return pool->volumes.objs[i];
return NULL;
}
virStorageVolDefPtr
virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
const char *path) {
unsigned int i;
for (i = 0 ; i < pool->volumes.count ; i++)
if (STREQ(pool->volumes.objs[i]->target.path, path))
return pool->volumes.objs[i];
return NULL;
}
virStorageVolDefPtr
virStorageVolDefFindByName(virStoragePoolObjPtr pool,
const char *name) {
unsigned int i;
for (i = 0 ; i < pool->volumes.count ; i++)
if (STREQ(pool->volumes.objs[i]->name, name))
return pool->volumes.objs[i];
return NULL;
}
virStoragePoolObjPtr
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
virStoragePoolDefPtr def) {
virStoragePoolObjPtr pool;
if ((pool = virStoragePoolObjFindByName(pools, def->name))) {
if (!virStoragePoolObjIsActive(pool)) {
virStoragePoolDefFree(pool->def);
pool->def = def;
} else {
virStoragePoolDefFree(pool->newDef);
pool->newDef = def;
}
return pool;
}
if (VIR_ALLOC(pool) < 0) {
virReportOOMError();
return NULL;
}
if (virMutexInit(&pool->lock) < 0) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("cannot initialize mutex"));
VIR_FREE(pool);
return NULL;
}
virStoragePoolObjLock(pool);
pool->active = 0;
pool->def = def;
if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
pool->def = NULL;
virStoragePoolObjUnlock(pool);
virStoragePoolObjFree(pool);
virReportOOMError();
return NULL;
}
pools->objs[pools->count++] = pool;
return pool;
}
static virStoragePoolObjPtr
virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
const char *file,
const char *path,
const char *autostartLink) {
virStoragePoolDefPtr def;
virStoragePoolObjPtr pool;
if (!(def = virStoragePoolDefParseFile(path))) {
return NULL;
}
if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
virStorageReportError(VIR_ERR_XML_ERROR,
_("Storage pool config filename '%s' does not match pool name '%s'"),
path, def->name);
virStoragePoolDefFree(def);
return NULL;
}
if (!(pool = virStoragePoolObjAssignDef(pools, def))) {
virStoragePoolDefFree(def);
return NULL;
}
VIR_FREE(pool->configFile); /* for driver reload */
pool->configFile = strdup(path);
if (pool->configFile == NULL) {
virReportOOMError();
virStoragePoolDefFree(def);
return NULL;
}
VIR_FREE(pool->autostartLink); /* for driver reload */
pool->autostartLink = strdup(autostartLink);
if (pool->autostartLink == NULL) {
virReportOOMError();
virStoragePoolDefFree(def);
return NULL;
}
pool->autostart = virFileLinkPointsTo(pool->autostartLink,
pool->configFile);
return pool;
}
int
virStoragePoolLoadAllConfigs(virStoragePoolObjListPtr pools,
const char *configDir,
const char *autostartDir) {
DIR *dir;
struct dirent *entry;
if (!(dir = opendir(configDir))) {
if (errno == ENOENT)
return 0;
virReportSystemError(errno, _("Failed to open dir '%s'"),
configDir);
return -1;
}
while ((entry = readdir(dir))) {
char *path;
char *autostartLink;
virStoragePoolObjPtr pool;
if (entry->d_name[0] == '.')
continue;
if (!virFileHasSuffix(entry->d_name, ".xml"))
continue;
if (!(path = virFileBuildPath(configDir, entry->d_name, NULL))) {
virReportOOMError();
continue;
}
if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
NULL))) {
virReportOOMError();
VIR_FREE(path);
continue;
}
pool = virStoragePoolObjLoad(pools, entry->d_name, path,
autostartLink);
if (pool)
virStoragePoolObjUnlock(pool);
VIR_FREE(path);
VIR_FREE(autostartLink);
}
closedir(dir);
return 0;
}
int
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
virStoragePoolObjPtr pool,
virStoragePoolDefPtr def) {
char *xml;
int fd = -1, ret = -1;
ssize_t towrite;
if (!pool->configFile) {
int err;
if ((err = virFileMakePath(driver->configDir))) {
virReportSystemError(err,
_("cannot create config directory %s"),
driver->configDir);
return -1;
}
if (!(pool->configFile = virFileBuildPath(driver->configDir,
def->name, ".xml"))) {
virReportOOMError();
return -1;
}
if (!(pool->autostartLink = virFileBuildPath(driver->autostartDir,
def->name, ".xml"))) {
virReportOOMError();
VIR_FREE(pool->configFile);
return -1;
}
}
if (!(xml = virStoragePoolDefFormat(def))) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("failed to generate XML"));
return -1;
}
if ((fd = open(pool->configFile,
O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR )) < 0) {
virReportSystemError(errno,
_("cannot create config file %s"),
pool->configFile);
goto cleanup;
}
towrite = strlen(xml);
if (safewrite(fd, xml, towrite) != towrite) {
virReportSystemError(errno,
_("cannot write config file %s"),
pool->configFile);
goto cleanup;
}
if (VIR_CLOSE(fd) < 0) {
virReportSystemError(errno,
_("cannot save config file %s"),
pool->configFile);
goto cleanup;
}
ret = 0;
cleanup:
VIR_FORCE_CLOSE(fd);
VIR_FREE(xml);
return ret;
}
int
virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool) {
if (!pool->configFile) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("no config file for %s"), pool->def->name);
return -1;
}
if (unlink(pool->configFile) < 0) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
_("cannot remove config for %s"),
pool->def->name);
return -1;
}
return 0;
}
virStoragePoolSourcePtr
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
{
virStoragePoolSourcePtr source;
if (VIR_REALLOC_N(list->sources, list->nsources+1) < 0) {
virReportOOMError();
return NULL;
}
source = &list->sources[list->nsources++];
memset(source, 0, sizeof(*source));
return source;
}
char *virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def)
{
virStoragePoolOptionsPtr options;
virBuffer buf = VIR_BUFFER_INITIALIZER;
const char *type;
int i;
options = virStoragePoolOptionsForPoolType(def->type);
if (options == NULL)
return NULL;
type = virStoragePoolTypeToString(def->type);
if (!type) {
virStorageReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("unexpected pool type"));
goto cleanup;
}
virBufferAddLit(&buf, "<sources>\n");
for (i = 0; i < def->nsources; i++) {
virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
}
virBufferAddLit(&buf, "</sources>\n");
if (virBufferError(&buf))
goto no_memory;
return virBufferContentAndReset(&buf);
no_memory:
virReportOOMError();
cleanup:
virBufferFreeAndReset(&buf);
return NULL;
}
/*
* virStoragePoolObjIsDuplicate:
* @doms : virStoragePoolObjListPtr to search
* @def : virStoragePoolDefPtr definition of pool to lookup
* @check_active: If true, ensure that pool is not active
*
* Returns: -1 on error
* 0 if pool is new
* 1 if pool is a duplicate
*/
int virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
virStoragePoolDefPtr def,
unsigned int check_active)
{
int ret = -1;
int dupPool = 0;
virStoragePoolObjPtr pool = NULL;
/* See if a Pool with matching UUID already exists */
pool = virStoragePoolObjFindByUUID(pools, def->uuid);
if (pool) {
/* UUID matches, but if names don't match, refuse it */
if (STRNEQ(pool->def->name, def->name)) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(pool->def->uuid, uuidstr);
virStorageReportError(VIR_ERR_OPERATION_FAILED,
_("pool '%s' is already defined with uuid %s"),
pool->def->name, uuidstr);
goto cleanup;
}
if (check_active) {
/* UUID & name match, but if Pool is already active, refuse it */
if (virStoragePoolObjIsActive(pool)) {
virStorageReportError(VIR_ERR_OPERATION_INVALID,
_("pool is already active as '%s'"),
pool->def->name);
goto cleanup;
}
}
dupPool = 1;
} else {
/* UUID does not match, but if a name matches, refuse it */
pool = virStoragePoolObjFindByName(pools, def->name);
if (pool) {
char uuidstr[VIR_UUID_STRING_BUFLEN];
virUUIDFormat(pool->def->uuid, uuidstr);
virStorageReportError(VIR_ERR_OPERATION_FAILED,
_("pool '%s' already exists with uuid %s"),
def->name, uuidstr);
goto cleanup;
}
}
ret = dupPool;
cleanup:
if (pool)
virStoragePoolObjUnlock(pool);
return ret;
}
void virStoragePoolObjLock(virStoragePoolObjPtr obj)
{
virMutexLock(&obj->lock);
}
void virStoragePoolObjUnlock(virStoragePoolObjPtr obj)
{
virMutexUnlock(&obj->lock);
}