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 -=| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list