]> xenbits.xensource.com Git - libvirt.git/commitdiff
Added main internal storage driver impl
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 20 Feb 2008 15:34:52 +0000 (15:34 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 20 Feb 2008 15:34:52 +0000 (15:34 +0000)
14 files changed:
ChangeLog
Makefile.maint
configure.in
include/libvirt/virterror.h
po/POTFILES.in
src/Makefile.am
src/libvirt.c
src/storage_backend.c [new file with mode: 0644]
src/storage_backend.h [new file with mode: 0644]
src/storage_conf.c [new file with mode: 0644]
src/storage_conf.h [new file with mode: 0644]
src/storage_driver.c [new file with mode: 0644]
src/storage_driver.h [new file with mode: 0644]
src/virterror.c

index 132032c95e5e2d9ef46b0b015414f2aba0cb5345..179174ca6fcc8e8f0bc68d84acab5ffb90f03c12 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+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
index 4b54bafc9ab9f93640b3eb258bced43f7174920e..39320df088896a56c18ea8b94f97aaaa4d5b80d7 100644 (file)
@@ -289,7 +289,7 @@ sc_two_space_separator_in_usage:
                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.
index 3c30a8ae7b4cf89d7e40bace0357fb4477826103..9155c77fccf5868a72db4170bfca02b0b4767efe 100644 (file)
@@ -689,6 +689,8 @@ AC_SUBST(CYGWIN_EXTRA_LIBADD)
 AC_SUBST(CYGWIN_EXTRA_PYTHON_LIBADD)
 AC_SUBST(MINGW_EXTRA_LDFLAGS)
 
+AC_SYS_LARGEFILE
+
 # very annoying
 rm -f COPYING
 cp COPYING.LIB COPYING
index fa9457796d2473fd0694ef740f599e93a2766b77..f28ce50ba56df0cdf15b8e8b2142246f73c6f33f 100644 (file)
@@ -136,6 +136,8 @@ typedef enum {
     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;
 
 /**
index a1e78fa8f927417bfecc70f025a7f44bcafe0a60..f6c4dd8fa185c6e0a1ed7d94149ef86dc714a708 100644 (file)
@@ -10,6 +10,9 @@ src/proxy_internal.c
 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
index d058465abfcd6555d615cd90b743ab029d5baa5a..7c06f0363ada969cca9f7a03cbc10b3e55fb6972 100644 (file)
@@ -58,6 +58,9 @@ CLIENT_SOURCES =                                              \
                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 =                                               \
index 7c9c297c139025ceb97675a214962f4ec3dbb934..9cd70bb399edd9a7407d0a746d25557dad5a542b 100644 (file)
@@ -37,6 +37,7 @@
 #include "xen_unified.h"
 #include "remote_internal.h"
 #include "qemu_driver.h"
+#include "storage_driver.h"
 #ifdef WITH_OPENVZ
 #include "openvz_driver.h"
 #endif
@@ -215,6 +216,7 @@ virInitialize(void)
 #ifdef WITH_OPENVZ
     if (openvzRegister() == -1) return -1;
 #endif
+    if (storageRegister() == -1) return -1;
 #ifdef WITH_REMOTE
     if (remoteRegister () == -1) return -1;
 #endif
diff --git a/src/storage_backend.c b/src/storage_backend.c
new file mode 100644 (file)
index 0000000..254d37f
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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:
+ */
diff --git a/src/storage_backend.h b/src/storage_backend.h
new file mode 100644 (file)
index 0000000..0ad5152
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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:
+ */
diff --git a/src/storage_conf.c b/src/storage_conf.c
new file mode 100644 (file)
index 0000000..8dfcde7
--- /dev/null
@@ -0,0 +1,1251 @@
+/*
+ * 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:
+ */
diff --git a/src/storage_conf.h b/src/storage_conf.h
new file mode 100644 (file)
index 0000000..9ed5e9f
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * 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:
+ */
diff --git a/src/storage_driver.c b/src/storage_driver.c
new file mode 100644 (file)
index 0000000..f97f706
--- /dev/null
@@ -0,0 +1,1261 @@
+/*
+ * 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:
+ */
diff --git a/src/storage_driver.h b/src/storage_driver.h
new file mode 100644 (file)
index 0000000..9c332bb
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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:
+ */
index 2629c37fc95a9c052c8f423b2641dad48bf05681..b2f860d4758b51105db7d5948d261d3ce97f7c21 100644 (file)
@@ -678,6 +678,18 @@ __virErrorMsg(virErrorNumber error, const char *info)
            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");