[Libvir] PATCH: 7/7 storage driver and local backend implementation

Daniel P. Berrange berrange at redhat.com
Mon Oct 29 04:00:45 UTC 2007


This patch introduces the main storage driver. This is quite a large driver and
so is split across several modules

 - storage_driver.c/.h   - implements the public API calls glueing together the
                           storage object handling, to the storage backend impls
 - storage_conf.c/.h     - routines for parsing & formating XML, and managing the
                           in-memory structs representing the storage objects.
 - storage_backend.h     - defines a contract for storage pool backends
 - storage_backend_XXX.c - one file each for disk, iscsi, lvm, dir storage pools

The storage_driver & storage_conf files are both structured to follow the same
style as the QEMU network driver. In fact the storage_conf file has many routines
that are 100% cut+paste from the QEMU driver. To address this obvious flaw I will
pull some of these routines out into separate modules which can be easily shared
between drivers. These are mostly convenience routines for dealing with file I/O
making directories & symlink comparisons.

At this time all the storage backends are empty stubs, except for the local
directory driver. Implementing new backends requires about 6-8 methods to be
provided - significantly less than the number of methods in the public libvirt
storage API, since most are handled higher up the stack. The directory pool
impl is sufficient to manage '/var/lib/xen/images' using raw files only.

As an example, lets create a pool to manage xen images...

    # cat > pool-xen.xml <<EOF
    <pool type="dir">
      <name>xenimages</name>
      <target dir="/var/lib/xen/images"/>
      <permissions>
        <mode>0700</mode>
        <owner>0</owner>
        <group>0</group>
      </permissions>
    </pool>
    EOF
    # virsh pool-define pool-xen.xml
    # virsh pool-list --all
    Name                 State      Autostart
    -----------------------------------------
    xenimages            inactive   no

Until a pool is started you can't do much with it. Starting a pool takes
care of mounting a disk, logging into the iSCSI server, or activating the
LVM volume. In the case of a local dir, activating it merely loads the
volumes from disk

    # virsh pool-autostart xenimages
    # virsh pool-start xenimages
    # virsh pool-list
    Name                 State      Autostart
    -----------------------------------------
    xenimages            active     yes

Now we can list volumes available in the pool...

    # virsh vol-list xenimages
    Name                 Type       Path
    -----------------------------------------


None there yet, so lets create one. Notice how can we create sparse vs
fully-allocate images by tweaking capacity vs allocation in the XML.
The permissions should inherit from the pool, but currently they're
compulsory.

    # cat > vol-demo.xml <<EOF
    <volume type="file">
      <name>demo</name>
      <capacity>10000000000000</capacity>
      <allocation>100000</allocation>
      <permissions>
        <mode>0700</mode>
        <owner>0</owner>
        <group>0</group>
      </permissions>
    </volume>
    EOF
    # virsh vol-create xenimages vol-demo.xml
    # virsh vol-list xenimages
    Name                 Type       Path
    -----------------------------------------
    demo                 file       /var/lib/xen/images/demo

And lets check the file was actually created...

    # ls -lsh /var/lib/xen/images
    total 108K
    108K -rwx------ 1 root root 1.3G Oct 28 22:32 demo


There's a bunch more virsh commands, but that's the interesting ones all
covered.

 b/src/storage_backend.h       |   57 +
 b/src/storage_backend_disk.c  |   73 ++
 b/src/storage_backend_disk.h  |   29 
 b/src/storage_backend_fs.c    |  258 ++++++++
 b/src/storage_backend_fs.h    |   30 
 b/src/storage_backend_iscsi.c |   75 ++
 b/src/storage_backend_iscsi.h |   29 
 b/src/storage_backend_lvm.c   |   74 ++
 b/src/storage_backend_lvm.h   |   29 
 b/src/storage_conf.c          | 1333 ++++++++++++++++++++++++++++++++++++++++++
 b/src/storage_conf.h          |  222 ++++++
 b/src/storage_driver.c        |  996 +++++++++++++++++++++++++++++++
 b/src/storage_driver.h        |    6 
 include/libvirt/virterror.h   |    3 
 src/Makefile.am               |    7 
 src/virterror.c               |   33 +
 16 files changed, 3254 insertions(+)



diff -r f57805779ece include/libvirt/virterror.h
--- a/include/libvirt/virterror.h	Sun Oct 28 22:45:04 2007 -0400
+++ b/include/libvirt/virterror.h	Sun Oct 28 22:45:04 2007 -0400
@@ -52,6 +52,7 @@ typedef enum {
     VIR_FROM_TEST,	/* Error from test driver */
     VIR_FROM_REMOTE,	/* Error from remote driver */
     VIR_FROM_OPENVZ,    /* Error from OpenVZ driver */
+    VIR_FROM_STORAGE,   /* Error from Storage driver */
 } virErrorDomain;
 
 
@@ -132,6 +133,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;
 
 /**
diff -r f57805779ece src/Makefile.am
--- a/src/Makefile.am	Sun Oct 28 22:45:04 2007 -0400
+++ b/src/Makefile.am	Sun Oct 28 22:45:04 2007 -0400
@@ -57,6 +57,13 @@ 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_iscsi.h storage_backend_iscsi.c \
+		storage_backend_disk.h storage_backend_disk.c \
+		storage_backend_fs.h storage_backend_fs.c \
+		storage_backend_lvm.h storage_backend_lvm.c \
 		util.c util.h
 
 SERVER_SOURCES = 						\
diff -r f57805779ece src/storage_backend.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend.h	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,57 @@
+#ifndef __VIR_STORAGE_BACKEND_H__
+#define __VIR_STORAGE_BACKEND_H__
+
+#include <libvirt/libvirt.h>
+#include "storage_conf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+    typedef int (*virStoragePoolBackendCreate)(virStoragePoolObjPtr pool);
+    typedef int (*virStoragePoolBackendStart)(virStoragePoolObjPtr pool);
+    typedef int (*virStoragePoolBackendStop)(virStoragePoolObjPtr pool);
+    typedef int (*virStoragePoolBackendDestroy)(virStoragePoolObjPtr pool);
+
+    typedef int (*virStoragePoolBackendGetInfo)(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info);
+    typedef int (*virStoragePoolBackendVolCreate)(virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
+    typedef int (*virStoragePoolBackendVolDelete)(virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
+    typedef int (*virStoragePoolBackendVolGetInfo)(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info);
+
+
+    typedef struct _virStoragePoolBackend virStoragePoolBackend;
+    typedef virStoragePoolBackend *virStoragePoolBackendPtr;
+
+    struct _virStoragePoolBackend {
+        int type;
+
+        virStoragePoolBackendCreate create;
+        virStoragePoolBackendStart start;
+        virStoragePoolBackendStop stop;
+        virStoragePoolBackendDestroy destroy;
+
+        virStoragePoolBackendGetInfo getInfo;
+        virStoragePoolBackendVolCreate volCreate;
+        virStoragePoolBackendVolDelete volDelete;
+        virStoragePoolBackendVolGetInfo volGetInfo;
+    };
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#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 -r f57805779ece src/storage_backend_disk.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_disk.c	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,73 @@
+#include "storage_backend_disk.h"
+
+
+static int virStoragePoolBackendDiskCreate(virStoragePoolObjPtr pool)
+{
+  /* create partition table, if not initialized */
+  return -1;
+}
+static int virStoragePoolBackendDiskStart(virStoragePoolObjPtr pool)
+{
+  /* partition names */
+  return -1;
+}
+static int virStoragePoolBackendDiskStop(virStoragePoolObjPtr pool)
+{
+  return -1;
+}
+static int virStoragePoolBackendDiskDestroy(virStoragePoolObjPtr pool)
+{
+  return -1;
+}
+
+static int virStoragePoolBackendDiskGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info)
+{
+  /* block size */
+  return -1;
+}
+
+
+static int virStoragePoolBackendDiskVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+  /* Add a partition */
+  return -1;
+}
+static int virStoragePoolBackendDiskVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+  /* delete a partition */
+  return -1;
+}
+static int virStoragePoolBackendDiskVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info)
+{
+  /* partition size */
+  return -1;
+}
+
+
+virStoragePoolBackend virStoragePoolBackendDisk = {
+  .type = VIR_STORAGE_POOL_DISK,
+
+  .create = virStoragePoolBackendDiskCreate,
+  .start = virStoragePoolBackendDiskStart,
+  .stop = virStoragePoolBackendDiskStop,
+  .destroy = virStoragePoolBackendDiskDestroy,
+
+  .getInfo = virStoragePoolBackendDiskGetInfo,
+  .volCreate = virStoragePoolBackendDiskVolCreate,
+  .volDelete = virStoragePoolBackendDiskVolDelete,
+  .volGetInfo = virStoragePoolBackendDiskVolGetInfo,
+};
+
+/*
+ * 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 -r f57805779ece src/storage_backend_disk.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_disk.h	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,29 @@
+#ifndef __VIR_STORAGE_BACKEND_DISK_H__
+#define __VIR_STORAGE_BACKEND_DISK_H__
+
+#include "storage_backend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern virStoragePoolBackend virStoragePoolBackendDisk;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __VIR_STORAGE_BACKEND_DISK_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 -r f57805779ece src/storage_backend_fs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_fs.c	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,258 @@
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "storage_backend_fs.h"
+
+
+static int virStoragePoolBackendFileSystemCreate(virStoragePoolObjPtr pool)
+{
+    /* format the block device, if not already  formatted */
+    return -1;
+}
+static int virStoragePoolBackendFileSystemStart(virStoragePoolObjPtr pool)
+{
+    DIR *dir;
+    struct dirent *ent;
+
+    if (virStorageEnsureDir(pool->def->target) < 0) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot statvfs path '%s': %d (%s)",
+                              pool->def->target, errno, strerror(errno));
+        return -1;
+    }
+
+    /* XXX mount volume for FS */
+
+    if (!(dir = opendir(pool->def->target))) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot open path '%s': %d (%s)",
+                              pool->def->target, errno, strerror(errno));
+        return -1;
+    }
+
+    while ((ent = readdir(dir)) != NULL) {
+        virStorageVolDefPtr vol;
+        struct stat sb;
+
+        if (ent->d_name[0] == '.')
+            continue;
+
+        vol = calloc(1, sizeof(virStorageVolDef));
+        if (vol == NULL)
+            goto no_memory;
+        vol->name = strdup(ent->d_name);
+        if (vol->name == NULL)
+            goto no_memory;
+        /* XXX other format probes */
+        vol->format = VIR_STORAGE_VOL_RAW;
+        vol->target = malloc(strlen(pool->def->target) + 1 + strlen(vol->name) + 1);
+        if (vol->target == NULL)
+            goto no_memory;
+        strcpy(vol->target, pool->def->target);
+        strcat(vol->target, "/");
+        strcat(vol->target, vol->name);
+
+        if (stat(vol->target, &sb) < 0) {
+            virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot stat file '%s': %d (%s)",
+                                  vol->target, errno, strerror(errno));
+            goto failed;
+        }
+
+        vol->capacity = sb.st_size;
+        vol->allocation = (unsigned long long)sb.st_blocks * (unsigned long long)512;
+        vol->perms.mode = sb.st_mode;
+        vol->perms.uid = sb.st_uid;
+        vol->perms.gid = sb.st_gid;
+
+        vol->next = pool->volumes;
+        pool->volumes = vol;
+        pool->nvolumes++;
+        continue;
+
+    no_memory:
+        virStorageReportError(NULL, VIR_ERR_NO_MEMORY, "volume");
+    failed:
+        if (vol->name) free(vol->name);
+        if (vol->target) free(vol->target);
+        free(vol);
+        goto cleanup;
+    }
+    closedir(dir);
+    return 0;
+
+ cleanup:
+    closedir(dir);
+    return -1;
+}
+
+static int virStoragePoolBackendFileSystemStop(virStoragePoolObjPtr pool)
+{
+    virStorageVolDefPtr vol;
+
+    vol = pool->volumes;
+    while (vol) {
+        virStorageVolDefPtr next = vol->next;
+        virStorageVolDefFree(vol);
+        vol = next;
+    }
+    pool->volumes = NULL;
+    pool->nvolumes = 0;
+
+    /* XXX Unmount the disk */
+    return 0;
+}
+static int virStoragePoolBackendFileSystemDestroy(virStoragePoolObjPtr pool)
+{
+    /* nada */
+    return -1;
+}
+
+
+static int virStoragePoolBackendFileSystemGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info)
+{
+    struct statvfs sb;
+
+    if (statvfs(pool->def->target, &sb) < 0) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot statvfs path '%s': %d (%s)",
+                              pool->def->target, errno, strerror(errno));
+        return -1;
+    }
+
+    if (virStoragePoolObjIsActive(pool))
+        info->state = VIR_STORAGE_POOL_ACTIVE;
+    else
+        info->state = VIR_STORAGE_POOL_INACTIVE;
+
+    info->capacity = (unsigned long long)sb.f_frsize * (unsigned long long)sb.f_blocks;
+    info->allocation = info->capacity - ((unsigned long long)sb.f_bfree * (unsigned long long)sb.f_bsize);
+
+    return -1;
+}
+
+static int virStoragePoolBackendFileSystemVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+    int fd;
+
+    vol->target = malloc(strlen(pool->def->target) + 1 + strlen(vol->name) + 1);
+    if (vol->target == NULL) {
+        virStorageReportError(NULL, VIR_ERR_NO_MEMORY, "target");
+        return -1;
+    }
+    strcpy(vol->target, pool->def->target);
+    strcat(vol->target, "/");
+    strcat(vol->target, vol->name);
+
+    if ((fd = open(vol->target, O_WRONLY | O_CREAT, vol->perms.mode)) < 0) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot create path '%s': %d (%s)",
+                              vol->target, errno, strerror(errno));
+        return -1;
+    }
+
+    /* Pre-allocate any data if requested */
+    if (vol->allocation) {
+        unsigned long long remain = vol->allocation;
+        char zeros[4096];
+        memset(zeros, 0, sizeof(zeros));
+        while (remain) {
+            int bytes = sizeof(zeros);
+            if (bytes > remain)
+                bytes = remain;
+            if ((bytes = write(fd, zeros, bytes)) < 0) {
+                virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot fill file '%s': %d (%s)",
+                                      vol->target, errno, strerror(errno));
+                close(fd);
+                return -1;
+            }
+            remain -= bytes;
+        }
+    }
+
+    /* Now seek to final size, possibly making the file sparse */
+    if (ftruncate(fd, vol->capacity) < 0) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot extend file '%s': %d (%s)",
+                              vol->target, errno, strerror(errno));
+        close(fd);
+        return -1;
+    }
+
+    if (close(fd) < 0) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot close file '%s': %d (%s)",
+                              vol->target, errno, strerror(errno));
+        return -1;
+    }
+
+    return 0;
+}
+
+static int virStoragePoolBackendFileSystemVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+    if (unlink(vol->target) < 0) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot unlink file '%s': %d (%s)",
+                              vol->target, errno, strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+static int virStoragePoolBackendFileSystemVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info)
+{
+    struct stat sb;
+
+    if (stat(vol->target, &sb) < 0) {
+        virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "cannot stat file '%s': %d (%s)",
+                              vol->target, errno, strerror(errno));
+        return -1;
+    }
+
+    info->type = VIR_STORAGE_POOL_FILE;
+    info->capacity = sb.st_size;
+    info->allocation = (unsigned long long)sb.st_blocks * (unsigned long long)512;
+
+    return 0;
+}
+
+
+virStoragePoolBackend virStoragePoolBackendFileSystem = {
+    .type = VIR_STORAGE_POOL_FS,
+
+    .create = virStoragePoolBackendFileSystemCreate,
+    .start = virStoragePoolBackendFileSystemStart,
+    .stop = virStoragePoolBackendFileSystemStop,
+    .destroy = virStoragePoolBackendFileSystemDestroy,
+
+    .getInfo = virStoragePoolBackendFileSystemGetInfo,
+    .volCreate = virStoragePoolBackendFileSystemVolCreate,
+    .volDelete = virStoragePoolBackendFileSystemVolDelete,
+    .volGetInfo = virStoragePoolBackendFileSystemVolGetInfo,
+};
+
+virStoragePoolBackend virStoragePoolBackendDirectory = {
+    .type = VIR_STORAGE_POOL_DIR,
+
+    .create = virStoragePoolBackendFileSystemCreate,
+    .start = virStoragePoolBackendFileSystemStart,
+    .stop = virStoragePoolBackendFileSystemStop,
+    .destroy = virStoragePoolBackendFileSystemDestroy,
+
+    .getInfo = virStoragePoolBackendFileSystemGetInfo,
+    .volCreate = virStoragePoolBackendFileSystemVolCreate,
+    .volDelete = virStoragePoolBackendFileSystemVolDelete,
+    .volGetInfo = virStoragePoolBackendFileSystemVolGetInfo,
+};
+
+/*
+ * 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 -r f57805779ece src/storage_backend_fs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_fs.h	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,30 @@
+#ifndef __VIR_STORAGE_BACKEND_FS_H__
+#define __VIR_STORAGE_BACKEND_FS_H__
+
+#include "storage_backend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern virStoragePoolBackend virStoragePoolBackendFileSystem;
+    extern virStoragePoolBackend virStoragePoolBackendDirectory;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __VIR_STORAGE_BACKEND_FS_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 -r f57805779ece src/storage_backend_iscsi.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_iscsi.c	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,75 @@
+#include "storage_backend_iscsi.h"
+
+
+static int virStoragePoolBackendISCSICreate(virStoragePoolObjPtr pool)
+{
+  /* nada */
+  return -1;
+}
+static int virStoragePoolBackendISCSIStart(virStoragePoolObjPtr pool)
+{
+  /* login to iscsi server */
+  /* list LUNs for target */
+  return -1;
+}
+static int virStoragePoolBackendISCSIStop(virStoragePoolObjPtr pool)
+{
+  /* logout of iscsi server */
+  return -1;
+}
+static int virStoragePoolBackendISCSIDestroy(virStoragePoolObjPtr pool)
+{
+  /* nada */
+  return -1;
+}
+
+static int virStoragePoolBackendISCSIGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info)
+{
+  /* target size - unavailable */
+  return -1;
+}
+
+static int virStoragePoolBackendISCSIVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+  /* Nada */
+  return -1;
+}
+static int virStoragePoolBackendISCSIVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+  /* Nada */
+  return -1;
+}
+static int virStoragePoolBackendISCSIVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info)
+{
+  /* block device size */
+  return -1;
+}
+
+
+virStoragePoolBackend virStoragePoolBackendISCSI = {
+  .type = VIR_STORAGE_POOL_ISCSI,
+
+  .create = virStoragePoolBackendISCSICreate,
+  .start = virStoragePoolBackendISCSIStart,
+  .stop = virStoragePoolBackendISCSIStop,
+  .destroy = virStoragePoolBackendISCSIDestroy,
+
+  .getInfo = virStoragePoolBackendISCSIGetInfo,
+  .volCreate = virStoragePoolBackendISCSIVolCreate,
+  .volDelete = virStoragePoolBackendISCSIVolDelete,
+  .volGetInfo = virStoragePoolBackendISCSIVolGetInfo,
+};
+
+/*
+ * 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 -r f57805779ece src/storage_backend_iscsi.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_iscsi.h	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,29 @@
+#ifndef __VIR_STORAGE_BACKEND_ISCSI_H__
+#define __VIR_STORAGE_BACKEND_ISCSI_H__
+
+#include "storage_backend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  extern virStoragePoolBackend virStoragePoolBackendISCSI;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __VIR_STORAGE_BACKEND_ISCSI_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 -r f57805779ece src/storage_backend_lvm.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_lvm.c	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,74 @@
+#include "storage_backend_lvm.h"
+
+
+static int virStoragePoolBackendLVMCreate(virStoragePoolObjPtr pool)
+{
+  /* vgcreate */
+  return -1;
+}
+static int virStoragePoolBackendLVMStart(virStoragePoolObjPtr pool)
+{
+  /* vgchange -y */
+  return -1;
+}
+static int virStoragePoolBackendLVMStop(virStoragePoolObjPtr pool)
+{
+  /* vgchange -n */
+  return -1;
+}
+static int virStoragePoolBackendLVMDestroy(virStoragePoolObjPtr pool)
+{
+  /* vgdestroy */
+  return -1;
+}
+
+static int virStoragePoolBackendLVMGetInfo(virStoragePoolObjPtr pool, virStoragePoolInfoPtr info)
+{
+  /* target size - unavailable */
+  return -1;
+}
+
+static int virStoragePoolBackendLVMVolCreate(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+  /* lvcreate */
+  return -1;
+}
+static int virStoragePoolBackendLVMVolDelete(virStoragePoolObjPtr pool, virStorageVolDefPtr vol)
+{
+  /* lvdestroy */
+  return -1;
+}
+static int virStoragePoolBackendLVMVolGetInfo(virStoragePoolObjPtr pool, virStorageVolDefPtr vol, virStorageVolInfoPtr info)
+{
+  /* lvdisplay */
+  return -1;
+}
+
+
+virStoragePoolBackend virStoragePoolBackendLVM = {
+  .type = VIR_STORAGE_POOL_LVM,
+
+  .create = virStoragePoolBackendLVMCreate,
+  .start = virStoragePoolBackendLVMStart,
+  .stop = virStoragePoolBackendLVMStop,
+  .destroy = virStoragePoolBackendLVMDestroy,
+
+  .getInfo = virStoragePoolBackendLVMGetInfo,
+  .volCreate = virStoragePoolBackendLVMVolCreate,
+  .volDelete = virStoragePoolBackendLVMVolDelete,
+  .volGetInfo = virStoragePoolBackendLVMVolGetInfo,
+};
+
+/*
+ * 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 -r f57805779ece src/storage_backend_lvm.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_lvm.h	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,29 @@
+#ifndef __VIR_STORAGE_BACKEND_LVM_H__
+#define __VIR_STORAGE_BACKEND_LVM_H__
+
+#include "storage_backend.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern virStoragePoolBackend virStoragePoolBackendLVM;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __VIR_STORAGE_BACKEND_LVM_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 -r f57805779ece src/storage_conf.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_conf.c	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,1333 @@
+
+#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 "storage_conf.h"
+#include "xml.h"
+#include "uuid.h"
+#include "buf.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, errorMessage);
+}
+
+/* Build up a fully qualfiied path for a config file to be
+ * associated with a persistent guest or network */
+static int
+virStorageMakeConfigPath(const char *configDir,
+                         const char *name,
+                         const char *ext,
+                         char *buf,
+                         unsigned int buflen) {
+    if ((strlen(configDir) + 1 + strlen(name) + (ext ? strlen(ext) : 0) + 1) > buflen)
+        return -1;
+
+    strcpy(buf, configDir);
+    strcat(buf, "/");
+    strcat(buf, name);
+    if (ext)
+        strcat(buf, ext);
+    return 0;
+}
+
+int
+virStorageEnsureDir(const char *path)
+{
+    struct stat st;
+    char parent[PATH_MAX];
+    char *p;
+    int err;
+
+    if (stat(path, &st) >= 0)
+        return 0;
+
+    strncpy(parent, path, PATH_MAX);
+    parent[PATH_MAX - 1] = '\0';
+
+    if (!(p = strrchr(parent, '/')))
+        return EINVAL;
+
+    if (p == parent)
+        return EPERM;
+
+    *p = '\0';
+
+    if ((err = virStorageEnsureDir(parent)))
+        return err;
+
+    if (mkdir(path, 0777) < 0 && errno != EEXIST)
+        return errno;
+
+    return 0;
+}
+
+
+static int
+compareFileToNameSuffix(const char *file,
+                        const char *name,
+                        const char *suffix) {
+    int filelen = strlen(file);
+    int namelen = strlen(name);
+    int suffixlen = strlen(suffix);
+
+    if (filelen == (namelen + suffixlen) &&
+        !strncmp(file, name, namelen) &&
+        !strncmp(file + namelen, suffix, suffixlen))
+        return 1;
+    else
+        return 0;
+}
+
+static int
+hasSuffix(const char *str,
+          const char *suffix)
+{
+    int len = strlen(str);
+    int suffixlen = strlen(suffix);
+
+    if (len < suffixlen)
+        return 0;
+
+    return strcmp(str + len - suffixlen, suffix) == 0;
+}
+
+static int
+checkLinkPointsTo(const char *checkLink,
+                  const char *checkDest)
+{
+    char dest[PATH_MAX];
+    char real[PATH_MAX];
+    char checkReal[PATH_MAX];
+    int n;
+    int passed = 0;
+
+    /* read the link destination */
+    if ((n = readlink(checkLink, dest, PATH_MAX)) < 0) {
+        switch (errno) {
+        case ENOENT:
+        case ENOTDIR:
+            break;
+
+        case EINVAL:
+            virStorageLog("Autostart file '%s' is not a symlink",
+                          checkLink);
+            break;
+
+        default:
+            virStorageLog("Failed to read autostart symlink '%s': %s",
+                          checkLink, strerror(errno));
+            break;
+        }
+
+        goto failed;
+    } else if (n >= PATH_MAX) {
+        virStorageLog("Symlink '%s' contents too long to fit in buffer",
+                      checkLink);
+        goto failed;
+    }
+
+    dest[n] = '\0';
+
+    /* make absolute */
+    if (dest[0] != '/') {
+        char dir[PATH_MAX];
+        char tmp[PATH_MAX];
+        char *p;
+
+        strncpy(dir, checkLink, PATH_MAX);
+        dir[PATH_MAX] = '\0';
+
+        if (!(p = strrchr(dir, '/'))) {
+            virStorageLog("Symlink path '%s' is not absolute", checkLink);
+            goto failed;
+        }
+
+        if (p == dir) /* handle unlikely root dir case */
+            p++;
+
+        *p = '\0';
+
+        if (virStorageMakeConfigPath(dir, dest, NULL, tmp, PATH_MAX) < 0) {
+            virStorageLog("Path '%s/%s' is too long", dir, dest);
+            goto failed;
+        }
+
+        strncpy(dest, tmp, PATH_MAX);
+        dest[PATH_MAX] = '\0';
+    }
+
+    /* canonicalize both paths */
+    if (!realpath(dest, real)) {
+        virStorageLog("Failed to expand path '%s' :%s",
+                      dest, strerror(errno));
+        strncpy(real, dest, PATH_MAX);
+        real[PATH_MAX] = '\0';
+    }
+
+    if (!realpath(checkDest, checkReal)) {
+        virStorageLog("Failed to expand path '%s' :%s",
+                      checkDest, strerror(errno));
+        strncpy(checkReal, checkDest, PATH_MAX);
+        checkReal[PATH_MAX] = '\0';
+    }
+
+    /* compare */
+    if (strcmp(checkReal, real) != 0) {
+        virStorageLog("Autostart link '%s' is not a symlink to '%s', ignoring",
+                      checkLink, checkReal);
+        goto failed;
+    }
+
+    passed = 1;
+
+ failed:
+    return passed;
+}
+
+static int
+virStorageReadFile(const char *path,
+                   char *buf,
+                   int maxlen) {
+    FILE *fh;
+    struct stat st;
+    int ret = 0;
+
+    if (!(fh = fopen(path, "r"))) {
+        virStorageLog("Failed to open file '%s': %s",
+                      path, strerror(errno));
+        goto error;
+    }
+
+    if (fstat(fileno(fh), &st) < 0) {
+        virStorageLog("Failed to stat file '%s': %s",
+                      path, strerror(errno));
+        goto error;
+    }
+
+    if (S_ISDIR(st.st_mode)) {
+        virStorageLog("Ignoring directory '%s' - clearly not a config file", path);
+        goto error;
+    }
+
+    if (st.st_size >= maxlen) {
+        virStorageLog("File '%s' is too large", path);
+        goto error;
+    }
+
+    if ((ret = fread(buf, st.st_size, 1, fh)) != 1) {
+        virStorageLog("Failed to read config file '%s': %s",
+                      path, strerror(errno));
+        goto error;
+    }
+
+    buf[st.st_size] = '\0';
+
+    ret = 1;
+
+ error:
+    if (fh)
+        fclose(fh);
+
+    return ret;
+}
+
+
+void virStorageVolDefFree(virStorageVolDefPtr def) {
+    if (def->name)
+        free(def->name);
+
+    if (def->format == VIR_STORAGE_VOL_QCOW2 &&
+        def->formatOpts.qcow2.passwd) {
+        free(def->formatOpts.qcow2.passwd);
+    }
+
+    if (def->target)
+        free(def->target);
+    if (def->perms.label)
+        free(def->perms.label);
+    free(def);
+}
+
+void virStoragePoolDefFree(virStoragePoolDefPtr def) {
+    if (def->name)
+        free(def->name);
+
+    if (def->srcType == VIR_STORAGE_POOL_SRC_REMOTE) {
+        if (def->src.remote.hostname)
+            free(def->src.remote.hostname);
+        if (def->src.remote.export)
+            free(def->src.remote.export);
+    } else {
+        int i;
+        for (i = 0 ; i < def->src.local.ndev ; i++) {
+            if (def->src.local.devs[i])
+                free(def->src.local.devs[i]);
+        }
+        free(def->src.local.devs);
+    }
+
+    if (def->target)
+        free(def->target);
+    if (def->perms.label)
+        free(def->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 virStoragePoolDefTypeFromString(const char *type) {
+    if (STREQ(type, "dir"))
+        return VIR_STORAGE_POOL_DIR;
+    else if (STREQ(type, "fs"))
+        return VIR_STORAGE_POOL_FS;
+    else if (STREQ(type, "lvm"))
+        return VIR_STORAGE_POOL_LVM;
+    else if (STREQ(type, "disk"))
+        return VIR_STORAGE_POOL_DISK;
+    else if (STREQ(type, "iscsi"))
+        return VIR_STORAGE_POOL_ISCSI;
+    return -1;
+}
+
+static const char *virStoragePoolDefTypeToString(int type) {
+    switch (type) {
+    case VIR_STORAGE_POOL_DIR:
+        return "dir";
+    case VIR_STORAGE_POOL_FS:
+        return "fs";
+    case VIR_STORAGE_POOL_LVM:
+        return "lvm";
+    case VIR_STORAGE_POOL_DISK:
+        return "disk";
+    case VIR_STORAGE_POOL_ISCSI:
+        return "iscsi";
+    }
+    return NULL;
+}
+
+static int virStorageVolDefFormatFromString(const char *format) {
+    if (STREQ(format, "raw"))
+        return VIR_STORAGE_VOL_RAW;
+    else if (STREQ(format, "qcow"))
+        return VIR_STORAGE_VOL_QCOW;
+    else if (STREQ(format, "qcow2"))
+        return VIR_STORAGE_VOL_QCOW2;
+    else if (STREQ(format, "vvfat"))
+        return VIR_STORAGE_VOL_VVFAT;
+    else if (STREQ(format, "vpc"))
+        return VIR_STORAGE_VOL_VPC;
+    else if (STREQ(format, "bochs"))
+        return VIR_STORAGE_VOL_BOCHS;
+    else if (STREQ(format, "dmg"))
+        return VIR_STORAGE_VOL_DMG;
+    else if (STREQ(format, "cloop"))
+        return VIR_STORAGE_VOL_CLOOP;
+    else if (STREQ(format, "vmdk"))
+        return VIR_STORAGE_VOL_VMDK;
+    else if (STREQ(format, "cow"))
+        return VIR_STORAGE_VOL_COW;
+
+    return -1;
+}
+
+static const char *virStorageVolDefFormatToString(int format) {
+    switch (format) {
+    case VIR_STORAGE_VOL_RAW:
+        return "raw";
+    case VIR_STORAGE_VOL_QCOW:
+        return "qcow";
+    case VIR_STORAGE_VOL_QCOW2:
+        return "qcow2";
+    case VIR_STORAGE_VOL_VVFAT:
+        return "vvfat";
+    case VIR_STORAGE_VOL_VPC:
+        return "vpc";
+    case VIR_STORAGE_VOL_BOCHS:
+        return "bochs";
+    case VIR_STORAGE_VOL_DMG:
+        return "dmg";
+    case VIR_STORAGE_VOL_CLOOP:
+        return "cloop";
+    case VIR_STORAGE_VOL_VMDK:
+        return "vmdk";
+    case VIR_STORAGE_VOL_COW:
+        return "cow";
+    }
+    return NULL;
+}
+
+static int virStoragePoolDefParseSrcLocal(virConnectPtr conn, xmlXPathContextPtr ctxt, virStoragePoolSrcLocalPtr src) {
+    double count;
+    xmlNodePtr *nodes;
+    int i;
+
+    if (virXPathNumber("count(/pool/source[@type='local'])", ctxt, &count) < 0) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source element");
+        return -1;
+    }
+
+    /* Arbitrary cap */
+    if (count > 50) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "too many source elements");
+        return -1;
+    }
+
+    src->ndev = (int)count;
+    src->devs = calloc(src->ndev, sizeof(char*));
+
+    if (virXPathNodeSet("/pool/source[@type='local']", ctxt, &nodes) < 0) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "cannot extract source nodes");
+        return -1;
+    }
+
+    for (i = 0 ; i < src->ndev ; i++) {
+        src->devs[i] = (char *)xmlGetProp(nodes[i], BAD_CAST "dev");
+        if (src->devs[i] == NULL) {
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source dev attribute");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int virStoragePoolDefParseSrcRemote(virConnectPtr conn, xmlXPathContextPtr ctxt, virStoragePoolSrcRemotePtr src) {
+    src->hostname = virXPathString("string(/pool/source/@host)", ctxt);
+    if (src->hostname == NULL) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source host attribute");
+        return -1;
+    }
+
+    src->export = virXPathString("string(/pool/source/@export)", ctxt);
+    if (src->export == NULL) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing source export attribute");
+        return -1;
+    }
+
+    return 0;
+}
+
+
+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;
+        printf("[%s]\n", mode);
+        perms->mode = strtol(mode, &end, 8);
+        if (end && *end) {
+        printf("[%s]\n", end);
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed octal mode");
+            return -1;
+        }
+    }
+
+    if (virXPathLong("number(/pool/permissions/owner)", ctxt, &v) < 0) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing owner element");
+        return -1;
+    }
+    perms->uid = (int)v;
+    if (virXPathLong("number(/pool/permissions/group)", ctxt, &v) < 0) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing owner element");
+        return -1;
+    }
+    perms->gid = (int)v;
+
+    perms->label = virXPathString("string(/pool/permissions/label)", ctxt);
+
+    return 0;
+}
+
+
+static virStoragePoolDefPtr virStoragePoolDefParseDoc(virConnectPtr conn, xmlXPathContextPtr ctxt, xmlNodePtr root) {
+    virStoragePoolDefPtr ret = calloc(1, sizeof(virStoragePoolDef));
+    xmlChar *type = NULL;
+    char *uuid = NULL;
+    char *srcType = NULL;
+    char *authType = NULL;
+
+    if (ret == 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");
+    ret->type = virStoragePoolDefTypeFromString((const char *)type);
+    if (ret->type < 0) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "unsupported storage pool %s", (const char *)type);
+        goto cleanup;
+    }
+    xmlFree(type);
+    type = NULL;
+
+    ret->name = virXPathString("string(/pool/name)", ctxt);
+    if (ret->name == 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 (type == VIR_STORAGE_POOL_DIR) {
+        ret->srcType = VIR_STORAGE_POOL_SRC_NONE;
+    } else {
+        srcType = virXPathString("string(/pool/source/@type)", ctxt);
+        if (srcType == NULL) {
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing type attribute on source element");
+            goto cleanup;
+        }
+        if (STREQ(srcType, "local")) {
+            ret->srcType = VIR_STORAGE_POOL_SRC_LOCAL;
+        } else {
+            ret->srcType = VIR_STORAGE_POOL_SRC_REMOTE;
+        }
+        free(srcType);
+        srcType = NULL;
+
+        if (ret->srcType == VIR_STORAGE_POOL_SRC_LOCAL) {
+            if (virStoragePoolDefParseSrcLocal(conn, ctxt, &ret->src.local) < 0)
+                goto cleanup;
+        } else {
+            if (virStoragePoolDefParseSrcRemote(conn, ctxt, &ret->src.remote) < 0)
+                goto cleanup;
+        }
+    }
+
+
+
+
+    authType = virXPathString("string(/pool/auth/@type)", ctxt);
+    if (authType == NULL) {
+        ret->authType = VIR_STORAGE_POOL_AUTH_NONE;
+    } else {
+        if (STREQ(authType, "chap")) {
+            ret->authType = VIR_STORAGE_POOL_AUTH_CHAP;
+        } else {
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "unknown auth type '%s'", (const char *)authType);
+            goto cleanup;
+        }
+        free(authType);
+        authType = NULL;
+    }
+
+    if (ret->srcType == VIR_STORAGE_POOL_AUTH_CHAP) {
+        if (virStoragePoolDefParseAuthChap(conn, ctxt, &ret->auth.chap) < 0)
+            goto cleanup;
+    }
+
+
+
+    if (ret->type == VIR_STORAGE_POOL_DIR ||
+        ret->type == VIR_STORAGE_POOL_FS) {
+        ret->target = virXPathString("string(/pool/target/@dir)", ctxt);
+        if (ret->target == NULL) {
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing target dir attribute");
+            goto cleanup;
+        }
+    } else if (ret->type == VIR_STORAGE_POOL_LVM) {
+        ret->target = virXPathString("string(/pool/target/@name)", ctxt);
+        if (ret->target == NULL) {
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing target name attribute");
+            goto cleanup;
+        }
+    }
+
+    if (virStoragePoolDefParsePerms(conn, ctxt, &ret->perms) < 0)
+        goto cleanup;
+
+    return ret;
+
+ cleanup:
+    if (uuid)
+        free(uuid);
+    if (type)
+        xmlFree(type);
+    if (srcType)
+        xmlFree(srcType);
+    if (authType)
+        xmlFree(authType);
+    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:
+    if (ctxt)
+        xmlXPathFreeContext(ctxt);
+    if (xml)
+        xmlFreeDoc(xml);
+    return NULL;
+}
+
+
+char *virStoragePoolDefFormat(virConnectPtr conn, virStoragePoolDefPtr def) {
+    virBufferPtr buf = virBufferNew(8192);
+    const char *type;
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    if (!buf)
+        goto no_memory;
+
+    type = virStoragePoolDefTypeToString(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 (def->srcType == VIR_STORAGE_POOL_SRC_LOCAL) {
+        int i;
+        for (i = 0 ; i < def->src.local.ndev ; i++) {
+            if (virBufferVSprintf(buf,"  <source type='local' dev='%s'/>\n",
+                                  def->src.local.devs[i]) < 0)
+                goto no_memory;
+        }
+    } else if (def->srcType == VIR_STORAGE_POOL_SRC_REMOTE) {
+        if (virBufferVSprintf(buf,"  <source type='remote' host='%s' export='%s'>\n",
+                              def->src.remote.hostname, def->src.remote.export) < 0)
+            goto no_memory;
+        if (def->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
+            if (virBufferVSprintf(buf,"  <auth type='chap' login='%s' passwd='%s'>\n",
+                                  def->auth.chap.login, def->auth.chap.passwd) < 0)
+                goto no_memory;
+        }
+        if (virBufferAdd(buf,"  </source>\n", -1) < 0)
+            goto no_memory;
+    }
+
+
+    if (def->target) {
+        if (def->type == VIR_STORAGE_POOL_DIR ||
+            def->type == VIR_STORAGE_POOL_FS) {
+            if (virBufferVSprintf(buf,"  <target dir='%s'/>\n", def->target) < 0)
+                goto no_memory;
+        } else if (def->type == VIR_STORAGE_POOL_LVM) {
+            if (virBufferVSprintf(buf,"  <target name='%s'/>\n", def->target) < 0)
+                goto no_memory;
+        }
+    }
+
+    if (virBufferAdd(buf,"  <permissions>\n", -1) < 0)
+        goto no_memory;
+    if (virBufferVSprintf(buf,"    <mode>0%o</mode>\n", def->perms.mode) < 0)
+        goto no_memory;
+    if (virBufferVSprintf(buf,"    <owner>%d</owner>\n", def->perms.uid) < 0)
+        goto no_memory;
+    if (virBufferVSprintf(buf,"    <group>%d</group>\n", def->perms.gid) < 0)
+        goto no_memory;
+
+    if (def->perms.label) {
+        if (virBufferVSprintf(buf,"    <label>%s</label>\n", def->perms.label) < 0)
+            goto no_memory;
+    }
+    if (virBufferAdd(buf,"  </permissions>\n", -1) < 0)
+        goto no_memory;
+
+    if (virBufferAdd(buf,"</pool>\n", -1) < 0)
+        goto no_memory;
+
+    return virBufferContentAndFree(buf);
+
+ no_memory:
+    virStorageReportError(conn, VIR_ERR_NO_MEMORY, "xml");
+ cleanup:
+    if (buf) 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 = 0700;
+    } else {
+        char *end;
+        printf("[%s]\n", mode);
+        perms->mode = strtol(mode, &end, 8);
+        if (end && *end) {
+        printf("[%s]\n", end);
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed octal mode");
+            return -1;
+        }
+    }
+
+    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 (virXPathLong("number(/volume/permissions/group)", ctxt, &v) < 0) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing owner element");
+        return -1;
+    }
+    perms->gid = (int)v;
+
+    perms->label = virXPathString("string(/volume/permissions/label)", ctxt);
+
+    return 0;
+}
+
+
+
+static virStorageVolDefPtr virStorageVolDefParseDoc(virConnectPtr conn, xmlXPathContextPtr ctxt, xmlNodePtr root) {
+    virStorageVolDefPtr ret = calloc(1, sizeof(virStorageVolDef));
+    xmlChar *type = NULL;
+    char *allocation = NULL;
+    char *capacity = NULL;
+    char *uuid = NULL;
+    char *formatType = NULL;
+    char *end;
+
+    if (ret == NULL)
+        return NULL;
+
+    if (STRNEQ((const char *)root->name, "volume")) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "unknown root element");
+        goto cleanup;
+    }
+
+    type = xmlGetProp(root, BAD_CAST "type");
+    if (STREQ((const char*)type, "file"))
+        ret->type = VIR_STORAGE_VOL_FILE;
+    else
+        ret->type = VIR_STORAGE_VOL_BLOCK;
+    xmlFree(type);
+    type = NULL;
+
+    ret->name = virXPathString("string(/volume/name)", ctxt);
+    if (ret->name == NULL) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing name element");
+        goto cleanup;
+    }
+
+    uuid = virXPathString("string(/volume/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;
+    }
+
+    capacity = virXPathString("string(/volume/capacity)", ctxt);
+    if (capacity == NULL) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "missing capacity element");
+        goto cleanup;
+    }
+    ret->capacity = strtoull(capacity, &end, 10);
+    if (end && *end) {
+        virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed capacity element");
+        goto cleanup;
+    }
+    free(capacity);
+    capacity = NULL;
+
+    allocation = virXPathString("string(/volume/allocation)", ctxt);
+    if (allocation) {
+        ret->allocation = strtoull(allocation, &end, 10);
+        if (end && *end) {
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "malformed allocation element");
+            goto cleanup;
+        }
+        free(allocation);
+        allocation = NULL;
+    }
+
+    formatType = virXPathString("string(/volume/format/@type)", ctxt);
+    if (formatType == NULL) {
+        ret->format = VIR_STORAGE_VOL_RAW;
+    } else {
+        ret->format = virStorageVolDefFormatFromString((const char *)formatType);
+        if (ret->format < 0) {
+            virStorageReportError(conn, VIR_ERR_XML_ERROR, "unsupported storage volume format %s", (const char *)formatType);
+            goto cleanup;
+        }
+        xmlFree(formatType);
+        formatType = NULL;
+    }
+
+    if (virStorageVolDefParsePerms(conn, ctxt, &ret->perms) < 0)
+        goto cleanup;
+
+    return ret;
+
+ cleanup:
+    if (allocation)
+        free(allocation);
+    if (capacity)
+        free(capacity);
+    if (uuid)
+        free(uuid);
+    if (type)
+        xmlFree(type);
+    if (formatType)
+        xmlFree(formatType);
+    virStorageVolDefFree(ret);
+    return NULL;
+}
+
+
+virStorageVolDefPtr virStorageVolDefParse(virConnectPtr conn, 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, ctxt, node);
+
+    xmlXPathFreeContext(ctxt);
+    xmlFreeDoc(xml);
+
+    return ret;
+
+ cleanup:
+    if (ctxt)
+        xmlXPathFreeContext(ctxt);
+    if (xml)
+        xmlFreeDoc(xml);
+    return NULL;
+}
+
+
+
+char *virStorageVolDefFormat(virConnectPtr conn, virStorageVolDefPtr def) {
+    virBufferPtr buf = virBufferNew(8192);
+    char uuid[VIR_UUID_STRING_BUFLEN];
+    if (!buf)
+        goto no_memory;
+
+    if (virBufferVSprintf(buf, "<volume type='%s'>\n", def->type == VIR_STORAGE_VOL_FILE ? "file" : "block") < 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 (def->type == VIR_STORAGE_VOL_FILE) {
+        const char *format = virStorageVolDefFormatToString(def->format);
+        if (format == NULL) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "unexpected volume format %s", def->format);
+            goto cleanup;
+        }
+        if (def->format == VIR_STORAGE_VOL_QCOW2) {
+            if (virBufferVSprintf(buf,"  <format type='%s'/>\n", format) < 0)
+                goto no_memory;
+            if (def->formatOpts.qcow2.compress) {
+                if (virBufferAdd(buf,"  <compressed/>\n", -1) < 0)
+                    goto no_memory;
+            }
+            if (def->formatOpts.qcow2.encrypted) {
+                if (virBufferAdd(buf,"  <encrypted/>\n", -1) < 0)
+                    goto no_memory;
+            }
+            if (virBufferAdd(buf,"  </format>\n", -1) < 0)
+                goto no_memory;
+        } else {
+            if (virBufferVSprintf(buf,"  <format type='%s'/>\n", format) < 0)
+                goto no_memory;
+        }
+    }
+
+    if (def->target) {
+        if (def->type == VIR_STORAGE_POOL_FILE) {
+            if (virBufferVSprintf(buf,"  <target file='%s'/>\n", def->target) < 0)
+                goto no_memory;
+        } else {
+            if (virBufferVSprintf(buf,"  <target dev='%s'/>\n", def->target) < 0)
+                goto no_memory;
+        }
+    }
+
+    if (virBufferAdd(buf,"  <permissions>\n", -1) < 0)
+        goto no_memory;
+    if (virBufferVSprintf(buf,"    <mode>0%o</mode>\n", def->perms.mode) < 0)
+        goto no_memory;
+    if (virBufferVSprintf(buf,"    <owner>%d</owner>\n", def->perms.uid) < 0)
+        goto no_memory;
+    if (virBufferVSprintf(buf,"    <group>%d</group>\n", def->perms.gid) < 0)
+        goto no_memory;
+
+    if (def->perms.label) {
+        if (virBufferVSprintf(buf,"    <label>%s</label>\n", def->perms.label) < 0)
+            goto no_memory;
+    }
+    if (virBufferAdd(buf,"  </permissions>\n", -1) < 0)
+        goto no_memory;
+
+    if (virBufferAdd(buf,"</volume>\n", -1) < 0)
+        goto no_memory;
+
+    return virBufferContentAndFree(buf);
+
+ no_memory:
+    virStorageReportError(conn, VIR_ERR_NO_MEMORY, "xml");
+ cleanup:
+    if (buf) 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;
+}
+
+
+virStorageVolDefPtr virStorageVolDefFindByUUID(virStoragePoolObjPtr pool,
+                                               const unsigned char *uuid) {
+    virStorageVolDefPtr vol = pool->volumes;
+
+    while (vol) {
+        if (!memcmp(vol->uuid, uuid, VIR_UUID_BUFLEN))
+          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++;
+    printf("inactive %d\n", 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 (!compareFileToNameSuffix(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 = checkLinkPointsTo(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[8192];
+        char path[PATH_MAX];
+        char autostartLink[PATH_MAX];
+
+        if (entry->d_name[0] == '.')
+            continue;
+
+        if (!hasSuffix(entry->d_name, ".xml"))
+            continue;
+
+        if (virStorageMakeConfigPath(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 (virStorageMakeConfigPath(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 (!virStorageReadFile(path, xml, sizeof(xml)))
+            continue;
+
+        virStoragePoolObjLoad(driver, entry->d_name, path, xml, autostartLink);
+    }
+
+    closedir(dir);
+
+    return 0;
+}
+
+int virStoragePoolObjSaveDef(virConnectPtr conn,
+                             virStorageDriverStatePtr driver,
+                             virStoragePoolObjPtr pool,
+                             virStoragePoolDefPtr def) {
+    char *xml;
+    int fd = -1, ret = -1;
+    int towrite;
+
+    if (!pool->configFile) {
+        int err;
+        char path[PATH_MAX];
+
+        if ((err = virStorageEnsureDir(driver->configDir))) {
+            virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                  "cannot create config directory %s: %s",
+                                  driver->configDir, strerror(err));
+            return -1;
+        }
+
+        if (virStorageMakeConfigPath(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 (virStorageMakeConfigPath(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, "configFile");
+            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 (write(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;
+}
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -r f57805779ece src/storage_conf.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_conf.h	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,222 @@
+
+#ifndef __VIR_STORAGE_DRIVER_H__
+#define __VIR_STORAGE_DRIVER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <libvirt/libvirt.h>
+#include "internal.h"
+
+    typedef struct _virStoragePerms virStoragePerms;
+    typedef virStoragePerms *virStoragePermsPtr;
+    struct _virStoragePerms {
+        int mode;
+        int uid;
+        int gid;
+        char *label;
+    };
+
+
+
+    enum virStorageVolType {
+        VIR_STORAGE_VOL_FILE,
+        VIR_STORAGE_VOL_BLOCK,
+    };
+
+    enum virStorageVolFormat {
+        VIR_STORAGE_VOL_RAW,
+        VIR_STORAGE_VOL_QCOW,
+        VIR_STORAGE_VOL_QCOW2,
+        VIR_STORAGE_VOL_VVFAT,
+        VIR_STORAGE_VOL_VPC,
+        VIR_STORAGE_VOL_BOCHS,
+        VIR_STORAGE_VOL_DMG,
+        VIR_STORAGE_VOL_CLOOP,
+        VIR_STORAGE_VOL_VMDK,
+        VIR_STORAGE_VOL_COW,
+    };
+
+    typedef struct _virStorageVolDef virStorageVolDef;
+    typedef virStorageVolDef *virStorageVolDefPtr;
+    struct _virStorageVolDef {
+        char *name;
+        unsigned char uuid[VIR_UUID_BUFLEN];
+        int type;
+        int format;
+        union {
+            struct {
+                int compress :1;
+                int encrypted :1;
+                char *passwd;
+            } qcow2;
+        } formatOpts;
+        virStoragePerms perms;
+        char *target;
+        unsigned long long allocation;
+        unsigned long long capacity;
+
+        virStorageVolDefPtr next;
+    };
+
+    enum virStoragePoolType {
+        VIR_STORAGE_POOL_DIR,
+        VIR_STORAGE_POOL_FS,
+        VIR_STORAGE_POOL_LVM,
+        VIR_STORAGE_POOL_DISK,
+        VIR_STORAGE_POOL_ISCSI,
+    };
+
+    enum virStoragePoolSrcType {
+        VIR_STORAGE_POOL_SRC_NONE,
+        VIR_STORAGE_POOL_SRC_LOCAL,
+        VIR_STORAGE_POOL_SRC_REMOTE,
+    };
+
+    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;
+    };
+
+    typedef struct _virStoragePoolSrcRemote virStoragePoolSrcRemote;
+    typedef virStoragePoolSrcRemote *virStoragePoolSrcRemotePtr;
+    struct _virStoragePoolSrcRemote {
+        char *hostname;
+        char *export;
+    };
+
+    typedef struct _virStoragePoolSrcLocal virStoragePoolSrcLocal;
+    typedef virStoragePoolSrcLocal *virStoragePoolSrcLocalPtr;
+    struct _virStoragePoolSrcLocal {
+        int ndev;
+        char **devs;
+    };
+
+    typedef struct _virStoragePoolDef virStoragePoolDef;
+    typedef virStoragePoolDef *virStoragePoolDefPtr;
+
+    struct _virStoragePoolDef {
+        /* General metadata */
+        char *name;
+        unsigned char uuid[VIR_UUID_BUFLEN];
+        int type; /* virStoragePoolType */
+
+
+        /* Source info */
+        int srcType; /* virStoragePoolSrcType */
+        union {
+            virStoragePoolSrcRemote remote;
+            virStoragePoolSrcLocal local;
+        } src;
+
+        int authType;  /* virStoragePoolAuthType */
+        union {
+            virStoragePoolAuthChap chap;
+        } auth;
+
+
+        /* Local filesystem mapping */
+        char *target;
+        virStoragePerms perms;
+    };
+
+    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;
+    }
+
+    int virStorageEnsureDir(const char *path);
+
+    void virStorageReportError(virConnectPtr conn, int code, const char *fmt, ...);
+
+    int virStoragePoolObjScanConfigs(virStorageDriverStatePtr driver);
+
+    virStoragePoolObjPtr virStoragePoolObjFindByUUID(virStorageDriverStatePtr driver,
+                                                     const unsigned char *uuid);
+    virStoragePoolObjPtr virStoragePoolObjFindByName(virStorageDriverStatePtr driver,
+                                                     const char *name);
+
+    virStorageVolDefPtr virStorageVolDefFindByUUID(virStoragePoolObjPtr pool,
+                                                   const unsigned char *uuid);
+    virStorageVolDefPtr virStorageVolDefFindByName(virStoragePoolObjPtr pool,
+                                                   const char *name);
+
+    virStoragePoolDefPtr virStoragePoolDefParse(virConnectPtr conn, const char *xml, const char *filename);
+    char *virStoragePoolDefFormat(virConnectPtr conn, virStoragePoolDefPtr def);
+
+    virStorageVolDefPtr virStorageVolDefParse(virConnectPtr conn, const char *xml, const char *filename);
+    char *virStorageVolDefFormat(virConnectPtr conn, 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);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#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 -r f57805779ece src/storage_driver.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_driver.c	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,996 @@
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <errno.h>
+
+#include "driver.h"
+#include "storage_driver.h"
+#include "storage_conf.h"
+
+#include "storage_backend.h"
+#include "storage_backend_iscsi.h"
+#include "storage_backend_lvm.h"
+#include "storage_backend_disk.h"
+#include "storage_backend_fs.h"
+
+#define storageLog(msg...) fprintf(stderr, msg)
+
+static virStorageDriverStatePtr driverState;
+static virStoragePoolBackendPtr backends[] = {
+    &virStoragePoolBackendDirectory,
+    &virStoragePoolBackendFileSystem,
+    &virStoragePoolBackendDisk,
+    &virStoragePoolBackendLVM,
+    &virStoragePoolBackendISCSI,
+};
+
+static int storageDriverShutdown(void);
+
+static virStoragePoolBackendPtr storageBackend(int type) {
+    int i;
+    for (i = 0 ; i < (sizeof(backends)/sizeof(backends[0])) ; i++)
+        if (backends[i]->type == type)
+            return backends[i];
+
+    virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, "missing backend for pool type %d", type);
+    return NULL;
+}
+
+
+static void storageDriverAutostart(virStorageDriverStatePtr driver) {
+    virStoragePoolObjPtr pool;
+
+    pool = driver->pools;
+    while (pool != NULL) {
+        virStoragePoolObjPtr next = pool->next;
+
+        if (pool->autostart &&
+            !virStoragePoolObjIsActive(pool)) {
+            virStoragePoolBackendPtr backend;
+            if ((backend = storageBackend(pool->def->type)) == NULL) {
+                storageLog("Missing backend %d",
+                           pool->def->type);
+                pool = next;
+                continue;
+            }
+
+            if (backend->start(pool) < 0) {
+                virErrorPtr err = virGetLastError();
+                storageLog("Failed to autostart storage pool '%s': %s",
+                           pool->def->name, err->message);
+            }
+            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);
+
+    /*
+    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");
+    if (base) 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 networks */
+    pool = driverState->pools;
+    while (pool) {
+        virStoragePoolObjPtr next = pool->next;
+        if (virStoragePoolObjIsActive(pool)) {
+            virStoragePoolBackendPtr backend;
+            if ((backend = storageBackend(pool->def->type)) == NULL) {
+                storageLog("Missing backend");
+                continue;
+            }
+
+            if (backend->stop(pool) < 0) {
+                virErrorPtr err = virGetLastError();
+                storageLog("Failed to stop storage pool '%s': %s",
+                           pool->def->name, err->message);
+            }
+        }
+        pool = next;
+    }
+
+    /* free inactive networks */
+    pool = driverState->pools;
+    while (pool) {
+        virStoragePoolObjPtr next = pool->next;
+        virStoragePoolObjFree(pool);
+        pool = next;
+    }
+    driverState->pools = NULL;
+    driverState->nactivePools = 0;
+    driverState->ninactivePools = 0;
+
+    if (driverState->configDir)
+        free(driverState->configDir);
+    if (driverState->autostartDir)
+        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 virDrvOpenStatus storageOpen(virConnectPtr conn,
+                                    const char *name 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;
+    printf("<<< %d \n", driver->nactivePools);
+    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]);
+    return -1;
+}
+
+static int storageNumDefinedPools(virConnectPtr conn) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)conn->storagePrivateData;
+    printf(">>> %d \n", driver->ninactivePools);
+    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]);
+    return -1;
+}
+
+static virStoragePoolPtr storagePoolCreate(virConnectPtr conn, const char *xml) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr )conn->storagePrivateData;
+    virStoragePoolDefPtr def;
+    virStoragePoolObjPtr pool;
+    virStoragePoolPtr ret;
+    virStoragePoolBackendPtr backend;
+
+    printf("Create %p %d %d\n", driver->pools, driver->nactivePools, driver->ninactivePools);
+    if (!(def = virStoragePoolDefParse(conn, xml, NULL)))
+        return NULL;
+
+    if ((backend = storageBackend(def->type)) == NULL) {
+        virStoragePoolDefFree(def);
+        return NULL;
+    }
+
+    if (!(pool = virStoragePoolObjAssignDef(conn, driver, def))) {
+        virStoragePoolDefFree(def);
+        return NULL;
+    }
+
+    if (backend->start(pool) < 0) {
+        virStoragePoolObjRemove(driver, pool);
+        return NULL;
+    }
+    pool->active = 1;
+    driver->nactivePools++;
+    driver->ninactivePools--;
+
+    ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+    printf("Created %p %d %d\n", driver->pools, driver->nactivePools, driver->ninactivePools);
+    return ret;
+}
+
+static virStoragePoolPtr storagePoolDefine(virConnectPtr conn, const char *xml) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr )conn->storagePrivateData;
+    virStoragePoolDefPtr def;
+    virStoragePoolObjPtr pool;
+    virStoragePoolPtr ret;
+    virStoragePoolBackendPtr backend;
+
+    if (!(def = virStoragePoolDefParse(conn, xml, NULL)))
+        return NULL;
+
+    if ((backend = storageBackend(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 (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) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+    virStoragePoolBackendPtr backend;
+
+    if (!pool) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage pool with matching uuid");
+        return -1;
+    }
+
+    if ((backend = storageBackend(pool->def->type)) == NULL) {
+        return -1;
+    }
+
+    if (virStoragePoolObjIsActive(pool)) {
+        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR, "pool already active");
+        return -1;
+    }
+    if (backend->start(pool) < 0)
+        return -1;
+
+    pool->active = 1;
+    driver->nactivePools++;
+    driver->ninactivePools--;
+
+    return 0;
+}
+
+static int storagePoolShutdown(virStoragePoolPtr obj) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+    virStoragePoolBackendPtr backend;
+
+    if (!pool) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no stoage pool with matching uuid");
+        return -1;
+    }
+
+    if ((backend = storageBackend(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->stop(pool) < 0)
+        return -1;
+
+    pool->active = 0;
+    driver->nactivePools--;
+    driver->ninactivePools++;
+
+    return 0;
+}
+
+static int storagePoolDestroy(virStoragePoolPtr obj) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+    virStoragePoolBackendPtr backend;
+    int ret = 0;
+
+    if (!pool) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no stoage pool with matching uuid");
+        return -1;
+    }
+
+    if ((backend = storageBackend(pool->def->type)) == NULL) {
+        return -1;
+    }
+
+    if (!virStoragePoolObjIsActive(pool)) {
+        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+                              "storage pool is not active");
+        return -1;
+    }
+    ret = backend->stop(pool);
+
+    if (ret == 0) {
+        pool->active = 0;
+        driver->nactivePools--;
+        driver->ninactivePools++;
+    }
+
+    virFreeStoragePool(obj->conn, obj);
+
+    return ret;
+}
+
+static int storagePoolGetInfo(virStoragePoolPtr obj, virStoragePoolInfoPtr info) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+    virStoragePoolBackendPtr backend;
+
+    if (!pool) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage pool with matching uuid");
+        return -1;
+    }
+
+    if ((backend = storageBackend(pool->def->type)) == NULL) {
+        return -1;
+    }
+
+    memset(info, 0, sizeof(virStoragePoolInfo));
+    if (pool->active)
+        info->state = VIR_STORAGE_POOL_ACTIVE;
+    else
+        info->state = VIR_STORAGE_POOL_INACTIVE;
+
+    return 0;
+}
+
+static char *storagePoolDumpXML(virStoragePoolPtr obj, 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) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_ARG,
+                              "pool has no config file");
+        return -1;
+    }
+
+    *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 = virStorageEnsureDir(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++) {
+        if (names[i]) {
+            free(names[i]);
+            names[i] = NULL;
+        }
+    }
+    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, vol->name, vol->uuid);
+}
+
+static virStorageVolPtr storageVolumeLookupByUUID(virStoragePoolPtr obj, const unsigned char *uuid) {
+    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 = virStorageVolDefFindByUUID(pool, uuid);
+
+    if (!vol) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage vol with matching name");
+        return NULL;
+    }
+
+    return virGetStorageVol(obj, vol->name, vol->uuid);
+}
+
+static virStorageVolPtr storageVolumeCreateXML(virStoragePoolPtr obj, const char *xmldesc, int flags ATTRIBUTE_UNUSED) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->uuid);
+    virStoragePoolBackendPtr 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 = storageBackend(pool->def->type)) == NULL)
+        return NULL;
+
+    vol = virStorageVolDefParse(obj->conn, 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->volCreate(pool, vol) < 0) {
+        virStorageVolDefFree(vol);
+        return NULL;
+    }
+
+    vol->next = pool->volumes;
+    pool->volumes = vol;
+    pool->nvolumes++;
+
+    return virGetStorageVol(obj, vol->name, vol->uuid);
+}
+
+static int storageVolumeDestroy(virStorageVolPtr obj) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->pool->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid);
+    virStoragePoolBackendPtr backend;
+    virStorageVolDefPtr vol, tmp, prev;
+
+    if (!pool) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage pool with matching uuid");
+        return -1;
+    }
+
+    if (!virStoragePoolObjIsActive(pool)) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR,
+                              "storage pool is not active");
+        return -1;
+    }
+
+    if ((backend = storageBackend(pool->def->type)) == NULL)
+        return -1;
+
+    vol = virStorageVolDefFindByName(pool, obj->name);
+
+    if (!vol) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage vol with matching name");
+        return -1;
+    }
+
+    if (backend->volDelete(pool, vol) < 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->pool->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid);
+    virStoragePoolBackendPtr backend;
+    virStorageVolDefPtr vol;
+
+    if (!pool) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage pool with matching uuid");
+        return -1;
+    }
+
+    if (!virStoragePoolObjIsActive(pool)) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR,
+                              "storage pool is not active");
+        return -1;
+    }
+
+    vol = virStorageVolDefFindByName(pool, obj->name);
+
+    if (!vol) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage vol with matching name");
+        return -1;
+    }
+
+    if ((backend = storageBackend(pool->def->type)) == NULL)
+        return -1;
+
+    return backend->volGetInfo(pool, vol, info);
+}
+
+static char *storageVolumeGetXMLDesc(virStorageVolPtr obj, int flags ATTRIBUTE_UNUSED) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->pool->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid);
+    virStorageVolDefPtr vol;
+
+    if (!pool) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage pool with matching uuid");
+        return NULL;
+    }
+
+    if (!virStoragePoolObjIsActive(pool)) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR,
+                              "storage pool is not active");
+        return NULL;
+    }
+
+    vol = virStorageVolDefFindByName(pool, obj->name);
+
+    if (!vol) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage vol with matching name");
+        return NULL;
+    }
+
+    return virStorageVolDefFormat(obj->pool->conn, vol);
+}
+
+static char *storageVolumeGetPath(virStorageVolPtr obj) {
+    virStorageDriverStatePtr driver = (virStorageDriverStatePtr)obj->pool->conn->storagePrivateData;
+    virStoragePoolObjPtr pool = virStoragePoolObjFindByUUID(driver, obj->pool->uuid);
+    virStorageVolDefPtr vol;
+    char *ret;
+
+    if (!pool) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage pool with matching uuid");
+        return NULL;
+    }
+
+    if (!virStoragePoolObjIsActive(pool)) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INTERNAL_ERROR,
+                              "storage pool is not active");
+        return NULL;
+    }
+
+    vol = virStorageVolDefFindByName(pool, obj->name);
+
+    if (!vol) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "no storage vol with matching name");
+        return NULL;
+    }
+
+    ret = strdup(vol->target);
+    if (ret == NULL) {
+        virStorageReportError(obj->pool->conn, VIR_ERR_NO_MEMORY, "path");
+        return NULL;
+    }
+    return ret;
+}
+
+
+
+
+
+static virStorageDriver storageDriver = {
+    "storage",
+    storageOpen,
+    storageClose,
+    storageNumPools,
+    storageListPools,
+    storageNumDefinedPools,
+    storageListDefinedPools,
+    storagePoolLookupByName,
+    storagePoolLookupByUUID,
+    storagePoolCreate,
+    storagePoolDefine,
+    storagePoolUndefine,
+    storagePoolStart,
+    storagePoolShutdown,
+    storagePoolDestroy,
+    storagePoolGetInfo,
+    storagePoolDumpXML,
+    storagePoolGetAutostart,
+    storagePoolSetAutostart,
+    storagePoolNumVolumes,
+    storagePoolListVolumes,
+    storageVolumeLookupByName,
+    storageVolumeLookupByUUID,
+    storageVolumeCreateXML,
+    storageVolumeDestroy,
+    storageVolumeGetInfo,
+    storageVolumeGetXMLDesc,
+    storageVolumeGetPath
+};
+
+
+static virStateDriver stateDriver = {
+    storageDriverStartup,
+    storageDriverShutdown,
+    storageDriverReload,
+    storageDriverActive,
+};
+
+int storageRegister(void) {
+    virRegisterStorageDriver(&storageDriver);
+    virRegisterStateDriver(&stateDriver);
+    return 0;
+}
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
+
diff -r f57805779ece src/storage_driver.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_driver.h	Sun Oct 28 22:45:04 2007 -0400
@@ -0,0 +1,6 @@
+
+
+#include "storage_conf.h"
+
+
+int storageRegister(void);
diff -r f57805779ece src/virterror.c
--- a/src/virterror.c	Sun Oct 28 22:45:04 2007 -0400
+++ b/src/virterror.c	Sun Oct 28 22:45:04 2007 -0400
@@ -280,6 +280,9 @@ virDefaultErrorFunc(virErrorPtr err)
         case VIR_FROM_REMOTE:
             dom = "Remote ";
             break;
+        case VIR_FROM_STORAGE:
+            dom = "Storage ";
+            break;
     }
     if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) {
         domain = err->dom->name;
@@ -652,6 +655,36 @@ __virErrorMsg(virErrorNumber error, cons
 	    else
 		errmsg = _("invalid MAC adress: %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");
+	    else
+	        errmsg = _("invalid storage pool pointer in %s");
+        break;
+    case VIR_ERR_INVALID_STORAGE_VOL:
+        if (info == NULL)
+            errmsg = _("invalid storage volume pointer in");
+	    else
+	        errmsg = _("invalid storage volume pointer in %s");
+        break;
+	case VIR_WAR_NO_STORAGE:
+	    if (info == NULL)
+            errmsg = _("Failed to find a storage driver");
+	    else
+            errmsg = _("Failed to find a storage driver: %s");
+	    break;
     }
     return (errmsg);
 }

-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 




More information about the libvir-list mailing list