+Wed Feb 20 10:26:27 EST 2008 Daniel P. Berrange <berrange@redhat.com>
+
+ * Makefile.maint: Add virStorageReportError to locale check rule
+ * configure.in: Turn on large file support
+ * po/POTFILES.in: Add storage driver files
+ * include/libvirt/virterror.h, src/virterror.c: Add more error codes
+ * src/storage_driver.c, src/storage_driver.h: Add impl of all the
+ storage APIs
+ * src/storage_conf.c, src/storage_conf.h: Support routines for
+ parsing and formatting XML, and persisting storage pool configs
+ * src/storage_backend.c, src/storage_backend.h: Contract for
+ internal storage backends to interface with driver
+ * src/Makefile.am: Add new storage source files to library build
+
Wed Feb 20 10:23:27 EST 2008 Daniel P. Berrange <berrange@redhat.com>
* src/virsh.c: Added convenience methods for creating pools
1>&2; exit 1; } || :
err_func_re = \
-(DISABLE_fprintf|qemudLog|(xmlRpc|vir(Xend|XML|Hash|Conf|Test|LibConn))Error)
+(DISABLE_fprintf|qemudLog|(xmlRpc|vir(Xend|XML|Hash|Conf|Test|LibConn|StorageReport))Error)
# Look for diagnostics that aren't marked for translation.
# This won't find any for which error's format string is on a separate line.
AC_SUBST(CYGWIN_EXTRA_PYTHON_LIBADD)
AC_SUBST(MINGW_EXTRA_LDFLAGS)
+AC_SYS_LARGEFILE
+
# very annoying
rm -f COPYING
cp COPYING.LIB COPYING
VIR_ERR_INVALID_STORAGE_POOL, /* invalid storage pool object */
VIR_ERR_INVALID_STORAGE_VOL, /* invalid storage vol object */
VIR_WAR_NO_STORAGE, /* failed to start storage */
+ VIR_ERR_NO_STORAGE_POOL, /* storage pool not found */
+ VIR_ERR_NO_STORAGE_VOL, /* storage pool not found */
} virErrorNumber;
/**
src/qemu_conf.c
src/qemu_driver.c
src/remote_internal.c
+src/storage_backend.c
+src/storage_conf.c
+src/storage_driver.c
src/sexpr.c
src/test.c
src/uuid.c
openvz_conf.c openvz_conf.h \
openvz_driver.c openvz_driver.h \
nodeinfo.h nodeinfo.c \
+ storage_conf.h storage_conf.c \
+ storage_driver.h storage_driver.c \
+ storage_backend.h storage_backend.c \
util.c util.h
SERVER_SOURCES = \
#include "xen_unified.h"
#include "remote_internal.h"
#include "qemu_driver.h"
+#include "storage_driver.h"
#ifdef WITH_OPENVZ
#include "openvz_driver.h"
#endif
#ifdef WITH_OPENVZ
if (openvzRegister() == -1) return -1;
#endif
+ if (storageRegister() == -1) return -1;
#ifdef WITH_REMOTE
if (remoteRegister () == -1) return -1;
#endif
--- /dev/null
+/*
+ * storage_backend.h: internal storage driver backend contract
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-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 <string.h>
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "util.h"
+
+#include "storage_backend.h"
+
+
+virStorageBackendPtr
+virStorageBackendForType(int type) {
+ virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("missing backend for pool type %d"), type);
+ return NULL;
+}
+
+virStorageBackendPoolOptionsPtr
+virStorageBackendPoolOptionsForType(int type) {
+ virStorageBackendPtr backend = virStorageBackendForType(type);
+ if (backend == NULL)
+ return NULL;
+ return &backend->poolOptions;
+}
+
+virStorageBackendVolOptionsPtr
+virStorageBackendVolOptionsForType(int type) {
+ virStorageBackendPtr backend = virStorageBackendForType(type);
+ if (backend == NULL)
+ return NULL;
+ return &backend->volOptions;
+}
+
+
+int
+virStorageBackendFromString(const char *type) {
+ virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unknown storage backend type %s"), type);
+ return -1;
+}
+
+const char *
+virStorageBackendToString(int type) {
+ virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
+ _("unknown storage backend type %d"), type);
+ return NULL;
+}
+
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/*
+ * storage_backend.h: internal storage driver backend contract
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-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>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_H__
+#define __VIR_STORAGE_BACKEND_H__
+
+#include <libvirt/libvirt.h>
+#include "storage_conf.h"
+
+
+typedef const char *(*virStorageVolFormatToString)(virConnectPtr conn,
+ int format);
+typedef int (*virStorageVolFormatFromString)(virConnectPtr conn,
+ const char *format);
+
+typedef const char *(*virStoragePoolFormatToString)(virConnectPtr conn,
+ int format);
+typedef int (*virStoragePoolFormatFromString)(virConnectPtr conn,
+ const char *format);
+
+
+typedef struct _virStorageBackendVolOptions virStorageBackendVolOptions;
+typedef virStorageBackendVolOptions *virStorageBackendVolOptionsPtr;
+struct _virStorageBackendVolOptions {
+ virStorageVolFormatToString formatToString;
+ virStorageVolFormatFromString formatFromString;
+};
+
+
+/* Flags to indicate mandatory components in the pool source */
+enum {
+ VIR_STORAGE_BACKEND_POOL_SOURCE_HOST = (1<<0),
+ VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE = (1<<1),
+ VIR_STORAGE_BACKEND_POOL_SOURCE_DIR = (1<<2),
+ VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER = (1<<3),
+};
+
+typedef struct _virStorageBackendPoolOptions virStorageBackendPoolOptions;
+typedef virStorageBackendPoolOptions *virStorageBackendPoolOptionsPtr;
+struct _virStorageBackendPoolOptions {
+ int flags;
+ virStoragePoolFormatToString formatToString;
+ virStoragePoolFormatFromString formatFromString;
+};
+
+typedef int (*virStorageBackendStartPool)(virConnectPtr conn, virStoragePoolObjPtr pool);
+typedef int (*virStorageBackendBuildPool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags);
+typedef int (*virStorageBackendRefreshPool)(virConnectPtr conn, virStoragePoolObjPtr pool);
+typedef int (*virStorageBackendStopPool)(virConnectPtr conn, virStoragePoolObjPtr pool);
+typedef int (*virStorageBackendDeletePool)(virConnectPtr conn, virStoragePoolObjPtr pool, unsigned int flags);
+
+typedef int (*virStorageBackendCreateVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
+typedef int (*virStorageBackendRefreshVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
+typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags);
+
+
+typedef struct _virStorageBackend virStorageBackend;
+typedef virStorageBackend *virStorageBackendPtr;
+
+struct _virStorageBackend {
+ int type;
+
+ virStorageBackendStartPool startPool;
+ virStorageBackendBuildPool buildPool;
+ virStorageBackendRefreshPool refreshPool;
+ virStorageBackendStopPool stopPool;
+ virStorageBackendDeletePool deletePool;
+
+ virStorageBackendCreateVol createVol;
+ virStorageBackendRefreshVol refreshVol;
+ virStorageBackendDeleteVol deleteVol;
+
+ virStorageBackendPoolOptions poolOptions;
+ virStorageBackendVolOptions volOptions;
+
+ int volType;
+};
+
+
+virStorageBackendPtr virStorageBackendForType(int type);
+virStorageBackendPoolOptionsPtr virStorageBackendPoolOptionsForType(int type);
+virStorageBackendVolOptionsPtr virStorageBackendVolOptionsForType(int type);
+int virStorageBackendFromString(const char *type);
+const char *virStorageBackendToString(int type);
+
+
+#endif /* __VIR_STORAGE_BACKEND_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/*
+ * storage_conf.c: config handling for storage driver
+ *
+ * Copyright (C) 2006-2008 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 <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/uri.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 "storage_conf.h"
+#include "storage_backend.h"
+#include "xml.h"
+#include "uuid.h"
+#include "buf.h"
+#include "util.h"
+
+#define virStorageLog(msg...) fprintf(stderr, msg)
+
+void
+virStorageReportError(virConnectPtr conn, int code, const char *fmt, ...) {
+ va_list args;
+ char errorMessage[1024];
+
+ if (fmt) {
+ va_start(args, fmt);
+ vsnprintf(errorMessage, sizeof(errorMessage)-1, fmt, args);
+ va_end(args);
+ } else {
+ errorMessage[0] = '\0';
+ }
+ virStorageLog("%s", errorMessage);
+ __virRaiseError(conn, NULL, NULL, VIR_FROM_STORAGE, code, VIR_ERR_ERROR,
+ NULL, NULL, NULL, -1, -1, "%s", errorMessage);
+}
+
+
+
+void
+virStorageVolDefFree(virStorageVolDefPtr def) {
+ int i;
+ free(def->name);
+ free(def->key);
+
+ for (i = 0 ; i < def->source.nextent ; i++) {
+ free(def->source.extents[i].path);
+ }
+ free(def->source.extents);
+
+ free(def->target.path);
+ free(def->target.perms.label);
+ free(def);
+}
+
+void
+virStoragePoolDefFree(virStoragePoolDefPtr def) {
+ int i;
+
+ free(def->name);
+ free(def->source.host.name);
+ for (i = 0 ; i < def->source.ndevice ; i++) {
+ free(def->source.devices[i].freeExtents);
+ free(def->source.devices[i].path);
+ }
+ free(def->source.devices);
+ free(def->source.dir);
+
+ if (def->source.authType == VIR_STORAGE_POOL_AUTH_CHAP) {
+ free(def->source.auth.chap.login);
+ free(def->source.auth.chap.passwd);
+ }
+
+ free(def->target.path);
+ free(def->target.perms.label);
+ free(def);
+}
+
+
+void
+virStoragePoolObjFree(virStoragePoolObjPtr obj) {
+ if (obj->def)
+ virStoragePoolDefFree(obj->def);
+ if (obj->newDef)
+ virStoragePoolDefFree(obj->newDef);
+
+ free(obj->configFile);
+ free(obj->autostartLink);
+ free(obj);
+}
+
+void
+virStoragePoolObjRemove(virStorageDriverStatePtr driver,
+ virStoragePoolObjPtr pool)
+{
+ virStoragePoolObjPtr prev = NULL, curr;
+
+ curr = driver->pools;
+ while (curr != pool) {
+ prev = curr;
+ curr = curr->next;
+ }
+
+ if (curr) {
+ if (prev)
+ prev->next = curr->next;
+ else
+ driver->pools = curr->next;
+
+ driver->ninactivePools--;
+ }
+
+ virStoragePoolObjFree(pool);
+}
+
+
+static int
+virStoragePoolDefParseAuthChap(virConnectPtr conn,
+ xmlXPathContextPtr ctxt,
+ virStoragePoolAuthChapPtr auth) {
+ auth->login = virXPathString("string(/pool/source/auth/@login)", ctxt);
+ if (auth->login == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing auth host attribute"));
+ return -1;
+ }
+
+ auth->passwd = virXPathString("string(/pool/source/auth/@passwd)", ctxt);
+ if (auth->passwd == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing auth passwd attribute"));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+virStoragePoolDefParsePerms(virConnectPtr conn,
+ xmlXPathContextPtr ctxt,
+ virStoragePermsPtr perms) {
+ char *mode;
+ long v;
+
+ mode = virXPathString("string(/pool/permissions/mode)", ctxt);
+ if (!mode) {
+ perms->mode = 0700;
+ } else {
+ char *end;
+ perms->mode = strtol(mode, &end, 8);
+ if (*end || perms->mode < 0 || perms->mode > 0777) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed octal mode"));
+ return -1;
+ }
+ }
+
+ if (virXPathNode("/pool/permissions/owner", ctxt) == NULL) {
+ perms->uid = getuid();
+ } else {
+ if (virXPathLong("number(/pool/permissions/owner)", ctxt, &v) < 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed owner element"));
+ return -1;
+ }
+ perms->uid = (int)v;
+ }
+
+ if (virXPathNode("/pool/permissions/group", ctxt) == NULL) {
+ perms->uid = getgid();
+ } else {
+ if (virXPathLong("number(/pool/permissions/group)", ctxt, &v) < 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed group element"));
+ return -1;
+ }
+ perms->gid = (int)v;
+ }
+
+ /* NB, we're ignoring missing labels here - they'll simply inherit */
+ perms->label = virXPathString("string(/pool/permissions/label)", ctxt);
+
+ return 0;
+}
+
+
+static virStoragePoolDefPtr
+virStoragePoolDefParseDoc(virConnectPtr conn,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr root) {
+ virStorageBackendPoolOptionsPtr options;
+ virStoragePoolDefPtr ret;
+ xmlChar *type = NULL;
+ char *uuid = NULL;
+ char *authType = NULL;
+
+ if ((ret = calloc(1, sizeof(virStoragePoolDef))) == NULL)
+ return NULL;
+
+ if (STRNEQ((const char *)root->name, "pool")) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("unknown root element"));
+ goto cleanup;
+ }
+
+ type = xmlGetProp(root, BAD_CAST "type");
+ if ((ret->type = virStorageBackendFromString((const char *)type)) < 0)
+ goto cleanup;
+ xmlFree(type);
+ type = NULL;
+
+ if ((options = virStorageBackendPoolOptionsForType(ret->type)) == NULL) {
+ goto cleanup;
+ }
+
+ if ((ret->name = virXPathString("string(/pool/name)", ctxt)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing name element"));
+ goto cleanup;
+ }
+
+ uuid = virXPathString("string(/pool/uuid)", ctxt);
+ if (uuid == NULL) {
+ if (virUUIDGenerate(ret->uuid) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unable to generate uuid"));
+ goto cleanup;
+ }
+ } else {
+ if (virUUIDParse(uuid, ret->uuid) < 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed uuid element"));
+ goto cleanup;
+ }
+ free(uuid);
+ uuid = NULL;
+ }
+
+ if (options->formatFromString) {
+ char *format = virXPathString("string(/pool/source/format/@type)", ctxt);
+ if ((ret->source.format = (options->formatFromString)(conn, format)) < 0) {
+ free(format);
+ goto cleanup;
+ }
+ free(format);
+ }
+
+ if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) {
+ if ((ret->source.host.name = virXPathString("string(/pool/source/host/@name)", ctxt)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing source host name"));
+ goto cleanup;
+ }
+ }
+ if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) {
+ xmlNodePtr *nodeset = NULL;
+ int nsource, i;
+
+ if ((nsource = virXPathNodeSet("/pool/source/device", ctxt, &nodeset)) <= 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("cannot extract source devices"));
+ goto cleanup;
+ }
+ if ((ret->source.devices = calloc(nsource, sizeof(*ret->source.devices))) == NULL) {
+ free(nodeset);
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("device"));
+ goto cleanup;
+ }
+ for (i = 0 ; i < nsource ; i++) {
+ xmlChar *path = xmlGetProp(nodeset[i], BAD_CAST "path");
+ if (path == NULL) {
+ free(nodeset);
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing source device path"));
+ goto cleanup;
+ }
+ ret->source.devices[i].path = (char *)path;
+ }
+ free(nodeset);
+ ret->source.ndevice = nsource;
+ }
+ if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) {
+ if ((ret->source.dir = virXPathString("string(/pool/source/dir/@path)", ctxt)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing source path"));
+ goto cleanup;
+ }
+ }
+
+
+ authType = virXPathString("string(/pool/source/auth/@type)", ctxt);
+ if (authType == NULL) {
+ ret->source.authType = VIR_STORAGE_POOL_AUTH_NONE;
+ } else {
+ if (STREQ(authType, "chap")) {
+ ret->source.authType = VIR_STORAGE_POOL_AUTH_CHAP;
+ } else {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("unknown auth type '%s'"),
+ (const char *)authType);
+ free(authType);
+ authType = NULL;
+ goto cleanup;
+ }
+ free(authType);
+ authType = NULL;
+ }
+
+ if (ret->source.authType == VIR_STORAGE_POOL_AUTH_CHAP) {
+ if (virStoragePoolDefParseAuthChap(conn, ctxt, &ret->source.auth.chap) < 0)
+ goto cleanup;
+ }
+
+ if ((ret->target.path = virXPathString("string(/pool/target/path)", ctxt)) == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing target path"));
+ goto cleanup;
+ }
+
+ if (virStoragePoolDefParsePerms(conn, ctxt, &ret->target.perms) < 0)
+ goto cleanup;
+
+ return ret;
+
+ cleanup:
+ free(uuid);
+ if (type)
+ xmlFree(type);
+ virStoragePoolDefFree(ret);
+ return NULL;
+}
+
+virStoragePoolDefPtr
+virStoragePoolDefParse(virConnectPtr conn,
+ const char *xmlStr,
+ const char *filename) {
+ virStoragePoolDefPtr ret = NULL;
+ xmlDocPtr xml = NULL;
+ xmlNodePtr node = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+
+ if (!(xml = xmlReadDoc(BAD_CAST xmlStr,
+ filename ? filename : "storage.xml",
+ NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed xml document"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("xmlXPathContext"));
+ goto cleanup;
+ }
+
+ node = xmlDocGetRootElement(xml);
+ if (node == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing root element"));
+ goto cleanup;
+ }
+
+ ret = virStoragePoolDefParseDoc(conn, ctxt, node);
+
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+
+ return ret;
+
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+ return NULL;
+}
+
+
+char *
+virStoragePoolDefFormat(virConnectPtr conn,
+ virStoragePoolDefPtr def) {
+ virStorageBackendPoolOptionsPtr options;
+ virBufferPtr buf;
+ const char *type;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ int i;
+
+ options = virStorageBackendPoolOptionsForType(def->type);
+ if (options == NULL)
+ return NULL;
+
+ if ((buf = virBufferNew(8192)) == NULL)
+ goto no_memory;
+
+ type = virStorageBackendToString(def->type);
+ if (!type) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unexpected pool type"));
+ goto cleanup;
+ }
+ if (virBufferVSprintf(buf, "<pool type='%s'>\n", type) < 0)
+ goto no_memory;
+
+ if (virBufferVSprintf(buf," <name>%s</name>\n", def->name) < 0)
+ goto no_memory;
+
+ virUUIDFormat(def->uuid, uuid);
+ if (virBufferVSprintf(buf," <uuid>%s</uuid>\n", uuid) < 0)
+ goto no_memory;
+
+ if (virBufferVSprintf(buf," <capacity>%llu</capacity>\n",
+ def->capacity) < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <allocation>%llu</allocation>\n",
+ def->allocation) < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <available>%llu</available>\n",
+ def->available) < 0)
+ goto no_memory;
+
+
+ if (virBufferAddLit(buf," <source>\n") < 0)
+ goto no_memory;
+ if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) &&
+ def->source.host.name &&
+ virBufferVSprintf(buf," <host name='%s'/>\n", def->source.host.name) < 0)
+ goto no_memory;
+ if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) &&
+ def->source.ndevice) {
+ for (i = 0 ; i < def->source.ndevice ; i++) {
+ if (virBufferVSprintf(buf," <device path='%s'>\n", def->source.devices[i].path) < 0)
+ goto no_memory;
+ if (def->source.devices[i].nfreeExtent) {
+ int j;
+ for (j = 0 ; j < def->source.devices[i].nfreeExtent ; j++) {
+ if (virBufferVSprintf(buf, " <freeExtent start='%llu' end='%llu'/>\n",
+ def->source.devices[i].freeExtents[j].start,
+ def->source.devices[i].freeExtents[j].end) < 0)
+ goto no_memory;
+ }
+ }
+ if (virBufferAddLit(buf," </device>\n") < 0)
+ goto no_memory;
+ }
+ }
+ if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) &&
+ def->source.dir &&
+ virBufferVSprintf(buf," <directory path='%s'/>\n", def->source.dir) < 0)
+ goto no_memory;
+ if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER) &&
+ def->source.adapter &&
+ virBufferVSprintf(buf," <adapter name='%s'/>\n", def->source.adapter) < 0)
+ goto no_memory;
+
+ if (options->formatToString) {
+ const char *format = (options->formatToString)(conn, def->source.format);
+ if (!format)
+ goto cleanup;
+ if (virBufferVSprintf(buf," <format type='%s'/>\n", format) < 0)
+ goto no_memory;
+ }
+
+
+ if (def->source.authType == VIR_STORAGE_POOL_AUTH_CHAP &&
+ virBufferVSprintf(buf," <auth type='chap' login='%s' passwd='%s'>\n",
+ def->source.auth.chap.login,
+ def->source.auth.chap.passwd) < 0)
+ goto no_memory;
+ if (virBufferAddLit(buf," </source>\n") < 0)
+ goto no_memory;
+
+
+
+ if (virBufferAddLit(buf," <target>\n") < 0)
+ goto no_memory;
+
+ if (def->target.path &&
+ virBufferVSprintf(buf," <path>%s</path>\n", def->target.path) < 0)
+ goto no_memory;
+
+ if (virBufferAddLit(buf," <permissions>\n") < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <mode>0%o</mode>\n",
+ def->target.perms.mode) < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <owner>%d</owner>\n",
+ def->target.perms.uid) < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <group>%d</group>\n",
+ def->target.perms.gid) < 0)
+ goto no_memory;
+
+ if (def->target.perms.label) {
+ if (virBufferVSprintf(buf," <label>%s</label>\n",
+ def->target.perms.label) < 0)
+ goto no_memory;
+ }
+ if (virBufferAddLit(buf," </permissions>\n") < 0)
+ goto no_memory;
+ if (virBufferAddLit(buf," </target>\n") < 0)
+ goto no_memory;
+
+ if (virBufferAddLit(buf,"</pool>\n") < 0)
+ goto no_memory;
+
+ return virBufferContentAndFree(buf);
+
+ no_memory:
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("xml"));
+ cleanup:
+ virBufferFree(buf);
+ return NULL;
+}
+
+
+static int
+virStorageVolDefParsePerms(virConnectPtr conn,
+ xmlXPathContextPtr ctxt,
+ virStoragePermsPtr perms) {
+ char *mode;
+ long v;
+
+ mode = virXPathString("string(/volume/permissions/mode)", ctxt);
+ if (!mode) {
+ perms->mode = 0600;
+ } else {
+ char *end = NULL;
+ perms->mode = strtol(mode, &end, 8);
+ if (*end || perms->mode < 0 || perms->mode > 0777) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed octal mode"));
+ return -1;
+ }
+ }
+
+ if (virXPathNode("/volume/permissions/owner", ctxt) == NULL) {
+ perms->uid = getuid();
+ } else {
+ if (virXPathLong("number(/volume/permissions/owner)", ctxt, &v) < 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing owner element"));
+ return -1;
+ }
+ perms->uid = (int)v;
+ }
+ if (virXPathNode("/volume/permissions/group", ctxt) == NULL) {
+ perms->gid = getgid();
+ } else {
+ if (virXPathLong("number(/volume/permissions/group)", ctxt, &v) < 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing owner element"));
+ return -1;
+ }
+ perms->gid = (int)v;
+ }
+
+ /* NB, we're ignoring missing labels here - they'll simply inherit */
+ perms->label = virXPathString("string(/volume/permissions/label)", ctxt);
+
+ return 0;
+}
+
+
+static int
+virStorageSize(virConnectPtr conn,
+ 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 'y':
+ case 'Y':
+ mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull *
+ 1024ull;
+ break;
+
+ case 'z':
+ case 'Z':
+ mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull *
+ 1024ull * 1024ull;
+ break;
+
+ default:
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("unknown size units '%s'"), unit);
+ return -1;
+ }
+ }
+
+ if (virStrToLong_ull (val, &end, 10, ret) < 0) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed capacity element"));
+ return -1;
+ }
+ if (*ret > (ULLONG_MAX / mult)) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("capacity element value too large"));
+ return -1;
+ }
+
+ *ret *= mult;
+
+ return 0;
+}
+
+static virStorageVolDefPtr
+virStorageVolDefParseDoc(virConnectPtr conn,
+ virStoragePoolDefPtr pool,
+ xmlXPathContextPtr ctxt,
+ xmlNodePtr root) {
+ virStorageVolDefPtr ret;
+ virStorageBackendVolOptionsPtr options;
+ char *allocation = NULL;
+ char *capacity = NULL;
+ char *unit = NULL;
+
+ options = virStorageBackendVolOptionsForType(pool->type);
+ if (options == NULL)
+ return NULL;
+
+ if ((ret = calloc(1, sizeof(virStorageVolDef))) == NULL)
+ return NULL;
+
+ if (STRNEQ((const char *)root->name, "volume")) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("unknown root element"));
+ goto cleanup;
+ }
+
+ ret->name = virXPathString("string(/volume/name)", ctxt);
+ if (ret->name == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing name element"));
+ goto cleanup;
+ }
+
+ /* Auto-generated so delibrately ignore */
+ /*ret->key = virXPathString("string(/volume/key)", ctxt);*/
+
+ capacity = virXPathString("string(/volume/capacity)", ctxt);
+ unit = virXPathString("string(/volume/capacity/@unit)", ctxt);
+ if (capacity == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing capacity element"));
+ goto cleanup;
+ }
+ if (virStorageSize(conn, unit, capacity, &ret->capacity) < 0)
+ goto cleanup;
+ free(capacity);
+ capacity = NULL;
+ free(unit);
+ unit = NULL;
+
+ allocation = virXPathString("string(/volume/allocation)", ctxt);
+ if (allocation) {
+ unit = virXPathString("string(/volume/allocation/@unit)", ctxt);
+ if (virStorageSize(conn, unit, allocation, &ret->allocation) < 0)
+ goto cleanup;
+ free(allocation);
+ allocation = NULL;
+ free(unit);
+ unit = NULL;
+ } else {
+ ret->allocation = ret->capacity;
+ }
+
+ ret->target.path = virXPathString("string(/volume/target/path)", ctxt);
+ if (options->formatFromString) {
+ char *format = virXPathString("string(/volume/target/format/@type)", ctxt);
+ if ((ret->target.format = (options->formatFromString)(conn, format)) < 0) {
+ free(format);
+ goto cleanup;
+ }
+ free(format);
+ }
+
+ if (virStorageVolDefParsePerms(conn, ctxt, &ret->target.perms) < 0)
+ goto cleanup;
+
+ return ret;
+
+ cleanup:
+ free(allocation);
+ free(capacity);
+ free(unit);
+ virStorageVolDefFree(ret);
+ return NULL;
+}
+
+
+virStorageVolDefPtr
+virStorageVolDefParse(virConnectPtr conn,
+ virStoragePoolDefPtr pool,
+ const char *xmlStr,
+ const char *filename) {
+ virStorageVolDefPtr ret = NULL;
+ xmlDocPtr xml = NULL;
+ xmlNodePtr node = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+
+ if (!(xml = xmlReadDoc(BAD_CAST xmlStr, filename ? filename : "storage.xml", NULL,
+ XML_PARSE_NOENT | XML_PARSE_NONET |
+ XML_PARSE_NOERROR | XML_PARSE_NOWARNING))) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("malformed xml document"));
+ goto cleanup;
+ }
+
+ ctxt = xmlXPathNewContext(xml);
+ if (ctxt == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("xmlXPathContext"));
+ goto cleanup;
+ }
+
+ node = xmlDocGetRootElement(xml);
+ if (node == NULL) {
+ virStorageReportError(conn, VIR_ERR_XML_ERROR,
+ _("missing root element"));
+ goto cleanup;
+ }
+
+ ret = virStorageVolDefParseDoc(conn, pool, ctxt, node);
+
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+
+ return ret;
+
+ cleanup:
+ xmlXPathFreeContext(ctxt);
+ xmlFreeDoc(xml);
+ return NULL;
+}
+
+
+
+char *
+virStorageVolDefFormat(virConnectPtr conn,
+ virStoragePoolDefPtr pool,
+ virStorageVolDefPtr def) {
+ virStorageBackendVolOptionsPtr options;
+ virBufferPtr buf = virBufferNew(8192);
+
+ options = virStorageBackendVolOptionsForType(pool->type);
+ if (options == NULL)
+ return NULL;
+
+ if (!buf)
+ goto no_memory;
+
+ if (virBufferAddLit(buf, "<volume>\n") < 0)
+ goto no_memory;
+
+ if (virBufferVSprintf(buf," <name>%s</name>\n", def->name) < 0)
+ goto no_memory;
+
+ if (virBufferVSprintf(buf," <key>%s</key>\n", def->key) < 0)
+ goto no_memory;
+
+ if (virBufferAddLit(buf, " <source>\n") < 0)
+ goto no_memory;
+ 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)
+ if (virBufferAddLit(buf, " </device>\n") < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf, " <device path='%s'>\n",
+ def->source.extents[i].path) < 0)
+ goto no_memory;
+ }
+
+ if (virBufferVSprintf(buf,
+ " <extent start='%llu' end='%llu'/>\n",
+ def->source.extents[i].start,
+ def->source.extents[i].end) < 0)
+ goto no_memory;
+ thispath = def->source.extents[i].path;
+ }
+ if (thispath != NULL)
+ if (virBufferAddLit(buf, " </device>\n") < 0)
+ goto no_memory;
+ }
+ if (virBufferAddLit(buf, " </source>\n") < 0)
+ goto no_memory;
+
+ if (virBufferVSprintf(buf," <capacity>%llu</capacity>\n",
+ def->capacity) < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <allocation>%llu</allocation>\n",
+ def->allocation) < 0)
+ goto no_memory;
+
+ if (virBufferAddLit(buf, " <target>\n") < 0)
+ goto no_memory;
+
+ if (def->target.path &&
+ virBufferVSprintf(buf," <path>%s</path>\n", def->target.path) < 0)
+ goto no_memory;
+
+ if (options->formatToString) {
+ const char *format = (options->formatToString)(conn,
+ def->target.format);
+ if (!format)
+ goto cleanup;
+ if (virBufferVSprintf(buf," <format type='%s'/>\n", format) < 0)
+ goto no_memory;
+ }
+
+ if (virBufferAddLit(buf," <permissions>\n") < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <mode>0%o</mode>\n",
+ def->target.perms.mode) < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <owner>%d</owner>\n",
+ def->target.perms.uid) < 0)
+ goto no_memory;
+ if (virBufferVSprintf(buf," <group>%d</group>\n",
+ def->target.perms.gid) < 0)
+ goto no_memory;
+
+ if (def->target.perms.label &&
+ virBufferVSprintf(buf," <label>%s</label>\n",
+ def->target.perms.label) < 0)
+ goto no_memory;
+ if (virBufferAddLit(buf," </permissions>\n") < 0)
+ goto no_memory;
+
+ if (virBufferAddLit(buf, " </target>\n") < 0)
+ goto no_memory;
+
+ if (virBufferAddLit(buf,"</volume>\n") < 0)
+ goto no_memory;
+
+ return virBufferContentAndFree(buf);
+
+ no_memory:
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("xml"));
+ cleanup:
+ virBufferFree(buf);
+ return NULL;
+}
+
+
+virStoragePoolObjPtr
+virStoragePoolObjFindByUUID(virStorageDriverStatePtr driver,
+ const unsigned char *uuid) {
+ virStoragePoolObjPtr pool = driver->pools;
+
+ while (pool) {
+ if (!memcmp(pool->def->uuid, uuid, VIR_UUID_BUFLEN))
+ return pool;
+ pool = pool->next;
+ }
+
+ return NULL;
+}
+
+virStoragePoolObjPtr
+virStoragePoolObjFindByName(virStorageDriverStatePtr driver,
+ const char *name) {
+ virStoragePoolObjPtr pool = driver->pools;
+
+ while (pool) {
+ if (STREQ(pool->def->name, name))
+ return pool;
+ pool = pool->next;
+ }
+
+ return NULL;
+}
+
+void
+virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
+{
+ virStorageVolDefPtr vol = pool->volumes;
+ while (vol) {
+ virStorageVolDefPtr next = vol->next;
+ virStorageVolDefFree(vol);
+ vol = next;
+ }
+ pool->volumes = NULL;
+ pool->nvolumes = 0;
+}
+
+virStorageVolDefPtr
+virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
+ const char *key) {
+ virStorageVolDefPtr vol = pool->volumes;
+
+ while (vol) {
+ if (STREQ(vol->key, key))
+ return vol;
+ vol = vol->next;
+ }
+
+ return NULL;
+}
+
+virStorageVolDefPtr
+virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
+ const char *path) {
+ virStorageVolDefPtr vol = pool->volumes;
+
+ while (vol) {
+ if (STREQ(vol->target.path, path))
+ return vol;
+ vol = vol->next;
+ }
+
+ return NULL;
+}
+
+virStorageVolDefPtr
+virStorageVolDefFindByName(virStoragePoolObjPtr pool,
+ const char *name) {
+ virStorageVolDefPtr vol = pool->volumes;
+
+ while (vol) {
+ if (STREQ(vol->name, name))
+ return vol;
+ vol = vol->next;
+ }
+
+ return NULL;
+}
+
+virStoragePoolObjPtr
+virStoragePoolObjAssignDef(virConnectPtr conn,
+ virStorageDriverStatePtr driver,
+ virStoragePoolDefPtr def) {
+ virStoragePoolObjPtr pool;
+
+ if ((pool = virStoragePoolObjFindByName(driver, def->name))) {
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStoragePoolDefFree(pool->def);
+ pool->def = def;
+ } else {
+ if (pool->newDef)
+ virStoragePoolDefFree(pool->newDef);
+ pool->newDef = def;
+ }
+ return pool;
+ }
+
+ if (!(pool = calloc(1, sizeof(virStoragePoolObj)))) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("pool"));
+ return NULL;
+ }
+
+ pool->active = 0;
+ pool->def = def;
+ pool->next = driver->pools;
+
+ driver->pools = pool;
+ driver->ninactivePools++;
+
+ return pool;
+}
+
+static virStoragePoolObjPtr
+virStoragePoolObjLoad(virStorageDriverStatePtr driver,
+ const char *file,
+ const char *path,
+ const char *xml,
+ const char *autostartLink) {
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool;
+
+ if (!(def = virStoragePoolDefParse(NULL, xml, file))) {
+ virErrorPtr err = virGetLastError();
+ virStorageLog("Error parsing storage pool config '%s' : %s",
+ path, err->message);
+ return NULL;
+ }
+
+ if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
+ virStorageLog("Storage pool config filename '%s' does not match pool name '%s'",
+ path, def->name);
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ if (!(pool = virStoragePoolObjAssignDef(NULL, driver, def))) {
+ virStorageLog("Failed to load storage pool config '%s': out of memory", path);
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ pool->configFile = strdup(path);
+ if (pool->configFile == NULL) {
+ virStorageLog("Failed to load storage pool config '%s': out of memory", path);
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+ pool->autostartLink = strdup(autostartLink);
+ if (pool->autostartLink == NULL) {
+ virStorageLog("Failed to load storage pool config '%s': out of memory", path);
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ pool->autostart = virFileLinkPointsTo(pool->autostartLink,
+ pool->configFile);
+
+ return pool;
+}
+
+
+int
+virStoragePoolObjScanConfigs(virStorageDriverStatePtr driver) {
+ DIR *dir;
+ struct dirent *entry;
+
+ if (!(dir = opendir(driver->configDir))) {
+ if (errno == ENOENT)
+ return 0;
+ virStorageLog("Failed to open dir '%s': %s",
+ driver->configDir, strerror(errno));
+ return -1;
+ }
+
+ while ((entry = readdir(dir))) {
+ char *xml = NULL;
+ char path[PATH_MAX];
+ char autostartLink[PATH_MAX];
+
+ if (entry->d_name[0] == '.')
+ continue;
+
+ if (!virFileHasSuffix(entry->d_name, ".xml"))
+ continue;
+
+ if (virFileBuildPath(driver->configDir, entry->d_name,
+ NULL, path, PATH_MAX) < 0) {
+ virStorageLog("Config filename '%s/%s' is too long",
+ driver->configDir, entry->d_name);
+ continue;
+ }
+
+ if (virFileBuildPath(driver->autostartDir, entry->d_name,
+ NULL, autostartLink, PATH_MAX) < 0) {
+ virStorageLog("Autostart link path '%s/%s' is too long",
+ driver->autostartDir, entry->d_name);
+ continue;
+ }
+
+ if (virFileReadAll(path, 8192, &xml) < 0)
+ continue;
+
+ virStoragePoolObjLoad(driver, entry->d_name, path, xml, autostartLink);
+
+ free(xml);
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+int
+virStoragePoolObjSaveDef(virConnectPtr conn,
+ virStorageDriverStatePtr driver,
+ virStoragePoolObjPtr pool,
+ virStoragePoolDefPtr def) {
+ char *xml;
+ int fd = -1, ret = -1;
+ ssize_t towrite;
+
+ if (!pool->configFile) {
+ int err;
+ char path[PATH_MAX];
+
+ if ((err = virFileMakePath(driver->configDir))) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create config directory %s: %s"),
+ driver->configDir, strerror(err));
+ return -1;
+ }
+
+ if (virFileBuildPath(driver->configDir, def->name, ".xml",
+ path, sizeof(path)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot construct config file path"));
+ return -1;
+ }
+ if (!(pool->configFile = strdup(path))) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("configFile"));
+ return -1;
+ }
+
+ if (virFileBuildPath(driver->autostartDir, def->name, ".xml",
+ path, sizeof(path)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot construct autostart link path"));
+ free(pool->configFile);
+ pool->configFile = NULL;
+ return -1;
+ }
+ if (!(pool->autostartLink = strdup(path))) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("config file"));
+ free(pool->configFile);
+ pool->configFile = NULL;
+ return -1;
+ }
+ }
+
+ if (!(xml = virStoragePoolDefFormat(conn, def))) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("failed to generate XML"));
+ return -1;
+ }
+
+ if ((fd = open(pool->configFile,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR )) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create config file %s: %s"),
+ pool->configFile, strerror(errno));
+ goto cleanup;
+ }
+
+ towrite = strlen(xml);
+ if (safewrite(fd, xml, towrite) != towrite) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot write config file %s: %s"),
+ pool->configFile, strerror(errno));
+ goto cleanup;
+ }
+
+ if (close(fd) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot save config file %s: %s"),
+ pool->configFile, strerror(errno));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (fd != -1)
+ close(fd);
+
+ free(xml);
+
+ return ret;
+}
+
+int
+virStoragePoolObjDeleteDef(virConnectPtr conn,
+ virStoragePoolObjPtr pool) {
+ if (!pool->configFile) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("no config file for %s"), pool->def->name);
+ return -1;
+ }
+
+ if (unlink(pool->configFile) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot remove config for %s"),
+ pool->def->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/*
+ * storage_conf.h: config handling for storage driver
+ *
+ * Copyright (C) 2006-2008 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>
+ */
+
+#ifndef __VIR_STORAGE_CONF_H__
+#define __VIR_STORAGE_CONF_H__
+
+#include <libvirt/libvirt.h>
+#include "internal.h"
+
+/* Shared structs */
+
+
+
+typedef struct _virStoragePerms virStoragePerms;
+typedef virStoragePerms *virStoragePermsPtr;
+struct _virStoragePerms {
+ int mode;
+ int uid;
+ int gid;
+ char *label;
+};
+
+/* Storage volumes */
+
+
+/*
+ * How the volume's data is stored on underlying
+ * physical devices - can potentially span many
+ * devices in LVM case.
+ */
+typedef struct _virStorageVolSourceExtent virStorageVolSourceExtent;
+typedef virStorageVolSourceExtent *virStorageVolSourceExtentPtr;
+struct _virStorageVolSourceExtent {
+ char *path;
+ unsigned long long start;
+ unsigned long long end;
+};
+
+typedef struct _virStorageVolSource virStorageVolSource;
+typedef virStorageVolSource *virStorageVolSourcePtr;
+struct _virStorageVolSource {
+ int nextent;
+ virStorageVolSourceExtentPtr extents;
+};
+
+
+/*
+ * How the volume appears on the host
+ */
+typedef struct _virStorageVolTarget virStorageVolTarget;
+typedef virStorageVolTarget *virStorageVolTargetPtr;
+struct _virStorageVolTarget {
+ char *path;
+ int format;
+ virStoragePerms perms;
+};
+
+
+typedef struct _virStorageVolDef virStorageVolDef;
+typedef virStorageVolDef *virStorageVolDefPtr;
+struct _virStorageVolDef {
+ char *name;
+ char *key;
+
+ unsigned long long allocation;
+ unsigned long long capacity;
+
+ virStorageVolSource source;
+ virStorageVolTarget target;
+
+ virStorageVolDefPtr next;
+};
+
+
+
+
+/* Storage pools */
+
+enum virStoragePoolType {
+ VIR_STORAGE_POOL_DIR = 1, /* Local directory */
+ VIR_STORAGE_POOL_FS, /* Local filesystem */
+ VIR_STORAGE_POOL_NETFS, /* Networked filesystem - eg NFS, GFS, etc */
+ VIR_STORAGE_POOL_LOGICAL, /* Logical volume groups / volumes */
+ VIR_STORAGE_POOL_DISK, /* Disk partitions */
+ VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */
+ VIR_STORAGE_POOL_SCSI, /* SCSI HBA */
+};
+
+
+enum virStoragePoolAuthType {
+ VIR_STORAGE_POOL_AUTH_NONE,
+ VIR_STORAGE_POOL_AUTH_CHAP,
+};
+
+typedef struct _virStoragePoolAuthChap virStoragePoolAuthChap;
+typedef virStoragePoolAuthChap *virStoragePoolAuthChapPtr;
+struct _virStoragePoolAuthChap {
+ char *login;
+ char *passwd;
+};
+
+
+/*
+ * For remote pools, info on how to reach the host
+ */
+typedef struct _virStoragePoolSourceHost virStoragePoolSourceHost;
+typedef virStoragePoolSourceHost *virStoragePoolSourceHostPtr;
+struct _virStoragePoolSourceHost {
+ char *name;
+ int port;
+ int protocol;
+};
+
+
+/*
+ * Available extents on the underlying storage
+ */
+typedef struct _virStoragePoolSourceDeviceExtent virStoragePoolSourceDeviceExtent;
+typedef virStoragePoolSourceDeviceExtent *virStoragePoolSourceDeviceExtentPtr;
+struct _virStoragePoolSourceDeviceExtent {
+ unsigned long long start;
+ unsigned long long end;
+};
+
+
+/*
+ * Pools can be backed by one or more devices, and some
+ * allow us to track free space on underlying devices.
+ */
+typedef struct _virStoragePoolSourceDevice virStoragePoolSourceDevice;
+typedef virStoragePoolSourceDevice *virStoragePoolSourceDevicePtr;
+struct _virStoragePoolSourceDevice {
+ int nfreeExtent;
+ virStoragePoolSourceDeviceExtentPtr freeExtents;
+ char *path;
+ int format; /* Pool specific source format */
+};
+
+
+
+typedef struct _virStoragePoolSource virStoragePoolSource;
+typedef virStoragePoolSource *virStoragePoolSourcePtr;
+struct _virStoragePoolSource {
+ /* An optional host */
+ virStoragePoolSourceHost host;
+
+ /* And either one or more devices ... */
+ int ndevice;
+ virStoragePoolSourceDevicePtr devices;
+
+ /* Or a directory */
+ char *dir;
+
+ /* Or an adapter */
+ char *adapter;
+
+ int authType; /* virStoragePoolAuthType */
+ union {
+ virStoragePoolAuthChap chap;
+ } auth;
+
+ int format; /* Pool type specific format such as filesystem type, or lvm version, etc */
+};
+
+
+typedef struct _virStoragePoolTarget virStoragePoolTarget;
+typedef virStoragePoolTarget *virStoragePoolTargetPtr;
+struct _virStoragePoolTarget {
+ char *path; /* Optional local filesystem mapping */
+ virStoragePerms perms; /* Default permissions for volumes */
+};
+
+
+typedef struct _virStoragePoolDef virStoragePoolDef;
+typedef virStoragePoolDef *virStoragePoolDefPtr;
+struct _virStoragePoolDef {
+ /* General metadata */
+ char *name;
+ unsigned char uuid[VIR_UUID_BUFLEN];
+ int type; /* virStoragePoolType */
+
+ unsigned long long allocation;
+ unsigned long long capacity;
+ unsigned long long available;
+
+ virStoragePoolSource source;
+ virStoragePoolTarget target;
+};
+
+typedef struct _virStoragePoolObj virStoragePoolObj;
+typedef virStoragePoolObj *virStoragePoolObjPtr;
+
+struct _virStoragePoolObj {
+ char *configFile;
+ char *autostartLink;
+ int active;
+ int autostart;
+
+ virStoragePoolDefPtr def;
+ virStoragePoolDefPtr newDef;
+
+ int nvolumes;
+ virStorageVolDefPtr volumes;
+
+ virStoragePoolObjPtr next;
+};
+
+
+
+
+typedef struct _virStorageDriverState virStorageDriverState;
+typedef virStorageDriverState *virStorageDriverStatePtr;
+
+struct _virStorageDriverState {
+ int nactivePools;
+ int ninactivePools;
+ virStoragePoolObjPtr pools;
+ char *configDir;
+ char *autostartDir;
+};
+
+
+static inline int virStoragePoolObjIsActive(virStoragePoolObjPtr pool) {
+ return pool->active;
+}
+
+void virStorageReportError(virConnectPtr conn,
+ int code,
+ const char *fmt, ...)
+ ATTRIBUTE_FORMAT(printf, 3, 4);
+
+int virStoragePoolObjScanConfigs(virStorageDriverStatePtr driver);
+
+virStoragePoolObjPtr virStoragePoolObjFindByUUID(virStorageDriverStatePtr driver,
+ const unsigned char *uuid);
+virStoragePoolObjPtr virStoragePoolObjFindByName(virStorageDriverStatePtr driver,
+ const char *name);
+
+virStorageVolDefPtr virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
+ const char *key);
+virStorageVolDefPtr virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
+ const char *path);
+virStorageVolDefPtr virStorageVolDefFindByName(virStoragePoolObjPtr pool,
+ const char *name);
+
+void virStoragePoolObjClearVols(virStoragePoolObjPtr pool);
+
+virStoragePoolDefPtr virStoragePoolDefParse(virConnectPtr conn,
+ const char *xml,
+ const char *filename);
+char *virStoragePoolDefFormat(virConnectPtr conn,
+ virStoragePoolDefPtr def);
+
+virStorageVolDefPtr virStorageVolDefParse(virConnectPtr conn,
+ virStoragePoolDefPtr pool,
+ const char *xml,
+ const char *filename);
+char *virStorageVolDefFormat(virConnectPtr conn,
+ virStoragePoolDefPtr pool,
+ virStorageVolDefPtr def);
+
+virStoragePoolObjPtr virStoragePoolObjAssignDef(virConnectPtr conn,
+ virStorageDriverStatePtr driver,
+ virStoragePoolDefPtr def);
+
+int virStoragePoolObjSaveDef(virConnectPtr conn,
+ virStorageDriverStatePtr driver,
+ virStoragePoolObjPtr pool,
+ virStoragePoolDefPtr def);
+int virStoragePoolObjDeleteDef(virConnectPtr conn,
+ virStoragePoolObjPtr pool);
+
+void virStorageVolDefFree(virStorageVolDefPtr def);
+void virStoragePoolDefFree(virStoragePoolDefPtr def);
+void virStoragePoolObjFree(virStoragePoolObjPtr pool);
+void virStoragePoolObjRemove(virStorageDriverStatePtr driver,
+ virStoragePoolObjPtr pool);
+
+#endif /* __VIR_STORAGE_DRIVER_H__ */
+
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/*
+ * storage_driver.c: core driver for storage APIs
+ *
+ * Copyright (C) 2006-2008 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 <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "driver.h"
+#include "util.h"
+#include "storage_driver.h"
+#include "storage_conf.h"
+
+#include "storage_backend.h"
+
+#define storageLog(msg...) fprintf(stderr, msg)
+
+static virStorageDriverStatePtr driverState;
+
+static int storageDriverShutdown(void);
+
+
+static void
+storageDriverAutostart(virStorageDriverStatePtr driver) {
+ virStoragePoolObjPtr pool;
+
+ pool = driver->pools;
+ while (pool != NULL) {
+ virStoragePoolObjPtr next = pool->next;
+
+ if (pool->autostart &&
+ !virStoragePoolObjIsActive(pool)) {
+ virStorageBackendPtr backend;
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ storageLog("Missing backend %d",
+ pool->def->type);
+ pool = next;
+ continue;
+ }
+
+ if (backend->startPool &&
+ backend->startPool(NULL, pool) < 0) {
+ virErrorPtr err = virGetLastError();
+ storageLog("Failed to autostart storage pool '%s': %s",
+ pool->def->name, err ? err->message : NULL);
+ pool = next;
+ continue;
+ }
+
+ if (backend->refreshPool(NULL, pool) < 0) {
+ virErrorPtr err = virGetLastError();
+ if (backend->stopPool)
+ backend->stopPool(NULL, pool);
+ storageLog("Failed to autostart storage pool '%s': %s",
+ pool->def->name, err ? err->message : NULL);
+ pool = next;
+ continue;
+ }
+ pool->active = 1;
+ driver->nactivePools++;
+ driver->ninactivePools--;
+ }
+
+ pool = next;
+ }
+}
+
+/**
+ * virStorageStartup:
+ *
+ * Initialization function for the QEmu daemon
+ */
+static int
+storageDriverStartup(void) {
+ uid_t uid = geteuid();
+ struct passwd *pw;
+ char *base = NULL;
+ char driverConf[PATH_MAX];
+
+ if (!(driverState = calloc(1, sizeof(virStorageDriverState)))) {
+ return -1;
+ }
+
+ if (!uid) {
+ if ((base = strdup (SYSCONF_DIR "/libvirt")) == NULL)
+ goto out_of_memory;
+ } else {
+ if (!(pw = getpwuid(uid))) {
+ storageLog("Failed to find user record for uid '%d': %s",
+ uid, strerror(errno));
+ goto out_of_memory;
+ }
+
+ if (asprintf (&base, "%s/.libvirt", pw->pw_dir) == -1) {
+ storageLog("out of memory in asprintf");
+ goto out_of_memory;
+ }
+ }
+
+ /* Configuration paths are either ~/.libvirt/storage/... (session) or
+ * /etc/libvirt/storage/... (system).
+ */
+ if (snprintf (driverConf, sizeof(driverConf),
+ "%s/storage.conf", base) == -1)
+ goto out_of_memory;
+ driverConf[sizeof(driverConf)-1] = '\0';
+
+ if (asprintf (&driverState->configDir,
+ "%s/storage", base) == -1)
+ goto out_of_memory;
+
+ if (asprintf (&driverState->autostartDir,
+ "%s/storage/autostart", base) == -1)
+ goto out_of_memory;
+
+ free(base);
+ base = NULL;
+
+ /*
+ if (virStorageLoadDriverConfig(driver, driverConf) < 0) {
+ virStorageDriverShutdown();
+ return -1;
+ }
+ */
+
+ if (virStoragePoolObjScanConfigs(driverState) < 0) {
+ storageDriverShutdown();
+ return -1;
+ }
+ storageDriverAutostart(driverState);
+
+ return 0;
+
+ out_of_memory:
+ storageLog("virStorageStartup: out of memory");
+ free(base);
+ free(driverState);
+ driverState = NULL;
+ return -1;
+}
+
+/**
+ * virStorageReload:
+ *
+ * Function to restart the storage driver, it will recheck the configuration
+ * files and update its state
+ */
+static int
+storageDriverReload(void) {
+ virStoragePoolObjScanConfigs(driverState);
+ storageDriverAutostart(driverState);
+
+ return 0;
+}
+
+/**
+ * virStorageActive:
+ *
+ * Checks if the storage driver is active, i.e. has an active pool
+ *
+ * Returns 1 if active, 0 otherwise
+ */
+static int
+storageDriverActive(void) {
+ /* If we've any active networks or guests, then we
+ * mark this driver as active
+ */
+ if (driverState->nactivePools)
+ return 1;
+
+ /* Otherwise we're happy to deal with a shutdown */
+ return 0;
+}
+
+/**
+ * virStorageShutdown:
+ *
+ * Shutdown the storage driver, it will stop all active storage pools
+ */
+static int
+storageDriverShutdown(void) {
+ virStoragePoolObjPtr pool;
+
+ if (!driverState)
+ return -1;
+
+ /* shutdown active pools */
+ pool = driverState->pools;
+ while (pool) {
+ virStoragePoolObjPtr next = pool->next;
+ if (virStoragePoolObjIsActive(pool)) {
+ virStorageBackendPtr backend;
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ storageLog("Missing backend");
+ continue;
+ }
+
+ if (backend->stopPool &&
+ backend->stopPool(NULL, pool) < 0) {
+ virErrorPtr err = virGetLastError();
+ storageLog("Failed to stop storage pool '%s': %s",
+ pool->def->name, err->message);
+ }
+ virStoragePoolObjClearVols(pool);
+ }
+ pool = next;
+ }
+
+ /* free inactive pools */
+ pool = driverState->pools;
+ while (pool) {
+ virStoragePoolObjPtr next = pool->next;
+ virStoragePoolObjFree(pool);
+ pool = next;
+ }
+ driverState->pools = NULL;
+ driverState->nactivePools = 0;
+ driverState->ninactivePools = 0;
+
+ free(driverState->configDir);
+ free(driverState->autostartDir);
+ free(driverState);
+ driverState = NULL;
+
+ return 0;
+}
+
+
+
+static virStoragePoolPtr
+storagePoolLookupByUUID(virConnectPtr conn,
+ const unsigned char *uuid) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, uuid);
+ virStoragePoolPtr ret;
+
+ if (!pool) {
+ virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL,
+ _("no pool with matching uuid"));
+ return NULL;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ return ret;
+}
+
+static virStoragePoolPtr
+storagePoolLookupByName(virConnectPtr conn,
+ const char *name) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, name);
+ virStoragePoolPtr ret;
+
+ if (!pool) {
+ virStorageReportError(conn, VIR_ERR_NO_STORAGE_POOL,
+ _("no pool with matching name"));
+ return NULL;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ return ret;
+}
+
+static virStoragePoolPtr
+storagePoolLookupByVolume(virStorageVolPtr vol) {
+ return storagePoolLookupByName(vol->conn, vol->pool);
+}
+
+static virDrvOpenStatus
+storageOpen(virConnectPtr conn,
+ xmlURIPtr uri ATTRIBUTE_UNUSED,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED) {
+ if (!driverState)
+ return VIR_DRV_OPEN_DECLINED;
+
+ conn->storagePrivateData = driverState;
+ return VIR_DRV_OPEN_SUCCESS;
+}
+
+static int
+storageClose(virConnectPtr conn) {
+ conn->storagePrivateData = NULL;
+ return 0;
+}
+
+static int
+storageNumPools(virConnectPtr conn) {
+ virStorageDriverStatePtr driver
+ = (virStorageDriverStatePtr)conn->storagePrivateData;
+ return driver->nactivePools;
+}
+
+static int
+storageListPools(virConnectPtr conn,
+ char **const names,
+ int nnames) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)conn->storagePrivateData;
+ virStoragePoolObjPtr pool = driver->pools;
+ int got = 0, i;
+ while (pool && got < nnames) {
+ if (virStoragePoolObjIsActive(pool)) {
+ if (!(names[got] = strdup(pool->def->name))) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("names"));
+ goto cleanup;
+ }
+ got++;
+ }
+ pool = pool->next;
+ }
+ return got;
+
+ cleanup:
+ for (i = 0 ; i < got ; i++) {
+ free(names[i]);
+ names[i] = NULL;
+ }
+ memset(names, 0, nnames);
+ return -1;
+}
+
+static int
+storageNumDefinedPools(virConnectPtr conn) {
+ virStorageDriverStatePtr driver
+ = (virStorageDriverStatePtr)conn->storagePrivateData;
+ return driver->ninactivePools;
+}
+
+static int
+storageListDefinedPools(virConnectPtr conn,
+ char **const names,
+ int nnames) {
+ virStorageDriverStatePtr driver
+ = (virStorageDriverStatePtr)conn->storagePrivateData;
+ virStoragePoolObjPtr pool = driver->pools;
+ int got = 0, i;
+ while (pool && got < nnames) {
+ if (!virStoragePoolObjIsActive(pool)) {
+ if (!(names[got] = strdup(pool->def->name))) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("names"));
+ goto cleanup;
+ }
+ got++;
+ }
+ pool = pool->next;
+ }
+ return got;
+
+ cleanup:
+ for (i = 0 ; i < got ; i++) {
+ free(names[i]);
+ names[i] = NULL;
+ }
+ memset(names, 0, nnames);
+ return -1;
+}
+
+static virStoragePoolPtr
+storagePoolCreate(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr )conn->storagePrivateData;
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret;
+ virStorageBackendPtr backend;
+
+ if (!(def = virStoragePoolDefParse(conn, xml, NULL)))
+ return NULL;
+
+ if (virStoragePoolObjFindByUUID(driver, def->uuid) ||
+ virStoragePoolObjFindByName(driver, def->name)) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool already exists"));
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ if ((backend = virStorageBackendForType(def->type)) == NULL) {
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ if (!(pool = virStoragePoolObjAssignDef(conn, driver, def))) {
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ if (backend->startPool(conn, pool) < 0) {
+ virStoragePoolObjRemove(driver, pool);
+ return NULL;
+ }
+ pool->active = 1;
+ driver->nactivePools++;
+ driver->ninactivePools--;
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+
+ return ret;
+}
+
+static virStoragePoolPtr
+storagePoolDefine(virConnectPtr conn,
+ const char *xml,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virStorageDriverStatePtr driver
+ = (virStorageDriverStatePtr )conn->storagePrivateData;
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret;
+ virStorageBackendPtr backend;
+
+ if (!(def = virStoragePoolDefParse(conn, xml, NULL)))
+ return NULL;
+
+ if ((backend = virStorageBackendForType(def->type)) == NULL) {
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ if (!(pool = virStoragePoolObjAssignDef(conn, driver, def))) {
+ virStoragePoolDefFree(def);
+ return NULL;
+ }
+
+ if (virStoragePoolObjSaveDef(conn, driver, pool, def) < 0) {
+ virStoragePoolObjRemove(driver, pool);
+ return NULL;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+ return ret;
+}
+
+static int
+storagePoolUndefine(virStoragePoolPtr obj) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if (virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("pool is still active"));
+ return -1;
+ }
+
+ if (virStoragePoolObjDeleteDef(obj->conn, pool) < 0)
+ return -1;
+
+ if (unlink(pool->autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR)
+ storageLog("Failed to delete autostart link '%s': %s",
+ pool->autostartLink, strerror(errno));
+
+ free(pool->configFile);
+ pool->configFile = NULL;
+ free(pool->autostartLink);
+ pool->autostartLink = NULL;
+
+ virStoragePoolObjRemove(driver, pool);
+
+ return 0;
+}
+
+static int
+storagePoolStart(virStoragePoolPtr obj,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageBackendPtr backend;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ return -1;
+ }
+
+ if (virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("pool already active"));
+ return -1;
+ }
+ if (backend->startPool &&
+ backend->startPool(obj->conn, pool) < 0)
+ return -1;
+ if (backend->refreshPool(obj->conn, pool) < 0) {
+ if (backend->stopPool)
+ backend->stopPool(obj->conn, pool);
+ return -1;
+ }
+
+ pool->active = 1;
+ driver->nactivePools++;
+ driver->ninactivePools--;
+
+ return 0;
+}
+
+static int
+storagePoolBuild(virStoragePoolPtr obj,
+ unsigned int flags) {
+ virStorageDriverStatePtr driver
+ = (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageBackendPtr backend;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ return -1;
+ }
+
+ if (virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is already active"));
+ return -1;
+ }
+
+ if (backend->buildPool &&
+ backend->buildPool(obj->conn, pool, flags) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+storagePoolDestroy(virStoragePoolPtr obj) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageBackendPtr backend;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ return -1;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return -1;
+ }
+
+ if (backend->stopPool &&
+ backend->stopPool(obj->conn, pool) < 0)
+ return -1;
+
+ virStoragePoolObjClearVols(pool);
+
+ pool->active = 0;
+ driver->nactivePools--;
+ driver->ninactivePools++;
+
+ if (pool->configFile == NULL)
+ virStoragePoolObjRemove(driver, pool);
+
+ return 0;
+}
+
+
+static int
+storagePoolDelete(virStoragePoolPtr obj,
+ unsigned int flags) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageBackendPtr backend;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ return -1;
+ }
+
+ if (virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is still active"));
+ return -1;
+ }
+
+ if (!backend->deletePool) {
+ virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
+ _("pool does not support volume delete"));
+ return -1;
+ }
+ if (backend->deletePool(obj->conn, pool, flags) < 0)
+ return -1;
+
+ return 0;
+}
+
+
+static int
+storagePoolRefresh(virStoragePoolPtr obj,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageBackendPtr backend;
+ int ret = 0;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ return -1;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return -1;
+ }
+
+ virStoragePoolObjClearVols(pool);
+ if ((ret = backend->refreshPool(obj->conn, pool)) < 0) {
+ if (backend->stopPool)
+ backend->stopPool(obj->conn, pool);
+
+ pool->active = 0;
+ driver->nactivePools--;
+ driver->ninactivePools++;
+
+ if (pool->configFile == NULL)
+ virStoragePoolObjRemove(driver, pool);
+ }
+
+ return ret;
+}
+
+
+static int
+storagePoolGetInfo(virStoragePoolPtr obj,
+ virStoragePoolInfoPtr info) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageBackendPtr backend;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL) {
+ return -1;
+ }
+
+ memset(info, 0, sizeof(virStoragePoolInfo));
+ if (pool->active)
+ info->state = VIR_STORAGE_POOL_RUNNING;
+ else
+ info->state = VIR_STORAGE_POOL_INACTIVE;
+ info->capacity = pool->def->capacity;
+ info->allocation = pool->def->allocation;
+ info->available = pool->def->available;
+
+ return 0;
+}
+
+static char *
+storagePoolDumpXML(virStoragePoolPtr obj,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return NULL;
+ }
+
+ return virStoragePoolDefFormat(obj->conn, pool->def);
+}
+
+static int
+storagePoolGetAutostart(virStoragePoolPtr obj,
+ int *autostart) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no pool with matching uuid"));
+ return -1;
+ }
+
+ if (!pool->configFile) {
+ *autostart = 0;
+ } else {
+ *autostart = pool->autostart;
+ }
+
+ return 0;
+}
+
+static int
+storagePoolSetAutostart(virStoragePoolPtr obj,
+ int autostart) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no pool with matching uuid"));
+ return -1;
+ }
+
+ if (!pool->configFile) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG,
+ _("pool has no config file"));
+ return -1;
+ }
+
+ autostart = (autostart != 0);
+
+ if (pool->autostart == autostart)
+ return 0;
+
+ if (autostart) {
+ int err;
+
+ if ((err = virFileMakePath(driver->autostartDir))) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create autostart directory %s: %s"),
+ driver->autostartDir, strerror(err));
+ return -1;
+ }
+
+ if (symlink(pool->configFile, pool->autostartLink) < 0) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to create symlink '%s' to '%s': %s"),
+ pool->autostartLink, pool->configFile,
+ strerror(errno));
+ return -1;
+ }
+ } else {
+ if (unlink(pool->autostartLink) < 0 &&
+ errno != ENOENT && errno != ENOTDIR) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("Failed to delete symlink '%s': %s"),
+ pool->autostartLink, strerror(errno));
+ return -1;
+ }
+ }
+
+ pool->autostart = autostart;
+
+ return 0;
+}
+
+
+static int
+storagePoolNumVolumes(virStoragePoolPtr obj) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return -1;
+ }
+
+ return pool->nvolumes;
+}
+
+static int
+storagePoolListVolumes(virStoragePoolPtr obj,
+ char **const names,
+ int maxnames) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ int i = 0;
+ virStorageVolDefPtr vol;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return -1;
+ }
+
+ memset(names, 0, maxnames);
+ vol = pool->volumes;
+ while (vol && i < maxnames) {
+ names[i] = strdup(vol->name);
+ if (names[i] == NULL) {
+ virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, _("name"));
+ goto cleanup;
+ }
+ vol = vol->next;
+ i++;
+ }
+
+ return i;
+
+ cleanup:
+ for (i = 0 ; i < maxnames ; i++) {
+ free(names[i]);
+ names[i] = NULL;
+ }
+ memset(names, 0, maxnames);
+ return -1;
+}
+
+
+static virStorageVolPtr
+storageVolumeLookupByName(virStoragePoolPtr obj,
+ const char *name) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageVolDefPtr vol;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return NULL;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return NULL;
+ }
+
+ vol = virStorageVolDefFindByName(pool, name);
+
+ if (!vol) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage vol with matching name"));
+ return NULL;
+ }
+
+ return virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key);
+}
+
+
+static virStorageVolPtr
+storageVolumeLookupByKey(virConnectPtr conn,
+ const char *key) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)conn->storagePrivateData;
+ virStoragePoolObjPtr pool = driver->pools;
+
+ while (pool) {
+ if (virStoragePoolObjIsActive(pool)) {
+ virStorageVolDefPtr vol = virStorageVolDefFindByKey(pool, key);
+
+ if (vol)
+ return virGetStorageVol(conn,
+ pool->def->name,
+ vol->name,
+ vol->key);
+ }
+ pool = pool->next;
+ }
+
+ virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
+ _("no storage vol with matching key"));
+ return NULL;
+}
+
+static virStorageVolPtr
+storageVolumeLookupByPath(virConnectPtr conn,
+ const char *path) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)conn->storagePrivateData;
+ virStoragePoolObjPtr pool = driver->pools;
+
+ while (pool) {
+ if (virStoragePoolObjIsActive(pool)) {
+ virStorageVolDefPtr vol = virStorageVolDefFindByPath(pool, path);
+
+ if (vol)
+ return virGetStorageVol(conn,
+ pool->def->name,
+ vol->name,
+ vol->key);
+ }
+ pool = pool->next;
+ }
+
+ virStorageReportError(conn, VIR_ERR_INVALID_STORAGE_VOL,
+ _("no storage vol with matching path"));
+ return NULL;
+}
+
+static virStorageVolPtr
+storageVolumeCreateXML(virStoragePoolPtr obj,
+ const char *xmldesc,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+ virStorageBackendPtr backend;
+ virStorageVolDefPtr vol;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return NULL;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return NULL;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
+ return NULL;
+
+ vol = virStorageVolDefParse(obj->conn, pool->def, xmldesc, NULL);
+ if (vol == NULL)
+ return NULL;
+
+ if (virStorageVolDefFindByName(pool, vol->name)) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("storage vol already exists"));
+ virStorageVolDefFree(vol);
+ return NULL;
+ }
+
+ if (!backend->createVol) {
+ virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
+ _("storage pool does not support volume creation"));
+ virStorageVolDefFree(vol);
+ return NULL;
+ }
+
+ if (backend->createVol(obj->conn, pool, vol) < 0) {
+ virStorageVolDefFree(vol);
+ return NULL;
+ }
+
+ vol->next = pool->volumes;
+ pool->volumes = vol;
+ pool->nvolumes++;
+
+ return virGetStorageVol(obj->conn, pool->def->name, vol->name, vol->key);
+}
+
+static int
+storageVolumeDelete(virStorageVolPtr obj,
+ unsigned int flags) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool);
+ virStorageBackendPtr backend;
+ virStorageVolDefPtr vol, tmp, prev;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
+ return -1;
+
+ vol = virStorageVolDefFindByName(pool, obj->name);
+
+ if (!vol) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage vol with matching name"));
+ return -1;
+ }
+
+ if (!backend->deleteVol) {
+ virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
+ _("storage pool does not support vol deletion"));
+ virStorageVolDefFree(vol);
+ return -1;
+ }
+
+ if (backend->deleteVol(obj->conn, pool, vol, flags) < 0) {
+ return -1;
+ }
+
+ prev = NULL;
+ tmp = pool->volumes;
+ while (tmp) {
+ if (tmp == vol) {
+ break;
+ }
+ prev = tmp;
+ tmp = tmp->next;
+ }
+ if (prev) {
+ prev->next = vol->next;
+ } else {
+ pool->volumes = vol->next;
+ }
+ pool->nvolumes--;
+ virStorageVolDefFree(vol);
+
+ return 0;
+}
+
+static int
+storageVolumeGetInfo(virStorageVolPtr obj,
+ virStorageVolInfoPtr info) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool);
+ virStorageBackendPtr backend;
+ virStorageVolDefPtr vol;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return -1;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return -1;
+ }
+
+ vol = virStorageVolDefFindByName(pool, obj->name);
+
+ if (!vol) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage vol with matching name"));
+ return -1;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
+ return -1;
+
+ if (backend->refreshVol &&
+ backend->refreshVol(obj->conn, pool, vol) < 0)
+ return -1;
+
+ memset(info, 0, sizeof(*info));
+ info->type = backend->volType;
+ info->capacity = vol->capacity;
+ info->allocation = vol->allocation;
+
+ return 0;
+}
+
+static char *
+storageVolumeGetXMLDesc(virStorageVolPtr obj,
+ unsigned int flags ATTRIBUTE_UNUSED) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool);
+ virStorageBackendPtr backend;
+ virStorageVolDefPtr vol;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return NULL;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return NULL;
+ }
+
+ vol = virStorageVolDefFindByName(pool, obj->name);
+
+ if (!vol) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage vol with matching name"));
+ return NULL;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
+ return NULL;
+
+ return virStorageVolDefFormat(obj->conn, pool->def, vol);
+}
+
+static char *
+storageVolumeGetPath(virStorageVolPtr obj) {
+ virStorageDriverStatePtr driver =
+ (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+ virStoragePoolObjPtr pool = virStoragePoolObjFindByName(driver, obj->pool);
+ virStorageVolDefPtr vol;
+ char *ret;
+
+ if (!pool) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ return NULL;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage pool is not active"));
+ return NULL;
+ }
+
+ vol = virStorageVolDefFindByName(pool, obj->name);
+
+ if (!vol) {
+ virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+ _("no storage vol with matching name"));
+ return NULL;
+ }
+
+ ret = strdup(vol->target.path);
+ if (ret == NULL) {
+ virStorageReportError(obj->conn, VIR_ERR_NO_MEMORY, _("path"));
+ return NULL;
+ }
+ return ret;
+}
+
+
+
+
+
+static virStorageDriver storageDriver = {
+ "storage",
+ storageOpen,
+ storageClose,
+ storageNumPools,
+ storageListPools,
+ storageNumDefinedPools,
+ storageListDefinedPools,
+ storagePoolLookupByName,
+ storagePoolLookupByUUID,
+ storagePoolLookupByVolume,
+ storagePoolCreate,
+ storagePoolDefine,
+ storagePoolBuild,
+ storagePoolUndefine,
+ storagePoolStart,
+ storagePoolDestroy,
+ storagePoolDelete,
+ storagePoolRefresh,
+ storagePoolGetInfo,
+ storagePoolDumpXML,
+ storagePoolGetAutostart,
+ storagePoolSetAutostart,
+ storagePoolNumVolumes,
+ storagePoolListVolumes,
+ storageVolumeLookupByName,
+ storageVolumeLookupByKey,
+ storageVolumeLookupByPath,
+ storageVolumeCreateXML,
+ storageVolumeDelete,
+ storageVolumeGetInfo,
+ storageVolumeGetXMLDesc,
+ storageVolumeGetPath
+};
+
+
+static virStateDriver stateDriver = {
+ storageDriverStartup,
+ storageDriverShutdown,
+ storageDriverReload,
+ storageDriverActive,
+};
+
+int storageRegister(void) {
+ virRegisterStorageDriver(&storageDriver);
+ virRegisterStateDriver(&stateDriver);
+ return 0;
+}
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/*
+ * storage_driver.h: core driver for storage APIs
+ *
+ * Copyright (C) 2006-2008 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>
+ */
+
+#ifndef __VIR_STORAGE_DRIVER_H__
+#define __VIR_STORAGE_DRIVER_H__
+
+#include "storage_conf.h"
+
+int storageRegister(void);
+
+#endif /* __VIR_STORAGE_DRIVER_H__ */
+
+/*
+ * vim: set tabstop=4:
+ * vim: set shiftwidth=4:
+ * vim: set expandtab:
+ */
+/*
+ * Local variables:
+ * indent-tabs-mode: nil
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
else
errmsg = _("authentication failed: %s");
break;
+ case VIR_ERR_NO_STORAGE_POOL:
+ if (info == NULL)
+ errmsg = _("Storage pool not found");
+ else
+ errmsg = _("Storage pool not found: %s");
+ break;
+ case VIR_ERR_NO_STORAGE_VOL:
+ if (info == NULL)
+ errmsg = _("Storage volume not found");
+ else
+ errmsg = _("Storage volume not found: %s");
+ break;
case VIR_ERR_INVALID_STORAGE_POOL:
if (info == NULL)
errmsg = _("invalid storage pool pointer in");