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 -=|