My previous patch for refactoring the storage backends broke the test driver's storage capabilities. The problem was that it made the backends private to the storage driver, but part of them was in fact needed by the XML parsers. This patch pulls a bunch of code out of the storage_backenmd file, and individual drivers and puts it straight into storage_conf.c/h for generic use by the parser. The storage backends are not totally private to the storage driver, and the test driver's storage impl still works Daniel diff -r 19c9bab70d15 src/Makefile.am --- a/src/Makefile.am Wed Nov 12 16:38:19 2008 +0000 +++ b/src/Makefile.am Wed Nov 12 21:05:13 2008 +0000 @@ -69,8 +69,7 @@ # Storage driver generic impl APIs STORAGE_CONF_SOURCES = \ - storage_conf.h storage_conf.c \ - storage_backend.h storage_backend.c + storage_conf.h storage_conf.c # The remote RPC driver, covering domains, storage, networks, etc @@ -123,7 +122,8 @@ # And finally storage backend specific impls STORAGE_DRIVER_SOURCES = \ - storage_driver.h storage_driver.c + storage_driver.h storage_driver.c \ + storage_backend.h storage_backend.c STORAGE_DRIVER_FS_SOURCES = \ storage_backend_fs.h storage_backend_fs.c diff -r 19c9bab70d15 src/storage_backend.c --- a/src/storage_backend.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend.c Wed Nov 12 21:05:13 2008 +0000 @@ -24,6 +24,7 @@ #include <config.h> #include <string.h> +#include <stdio.h> #if HAVE_REGEX_H #include <regex.h> #endif @@ -60,10 +61,6 @@ #include "storage_backend_fs.h" #endif -VIR_ENUM_IMPL(virStorageBackendPartTable, - VIR_STORAGE_POOL_DISK_LAST, - "unknown", "dos", "dvh", "gpt", - "mac", "bsd", "pc98", "sun", "lvm2"); static virStorageBackendPtr backends[] = { #if WITH_STORAGE_DIR @@ -95,81 +92,6 @@ virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, _("missing backend for pool type %d"), type); - return NULL; -} - -virStorageBackendPoolOptionsPtr -virStorageBackendPoolOptionsForType(int type) { - virStorageBackendPtr backend = virStorageBackendForType(type); - if (backend == NULL) - return NULL; - return &backend->poolOptions; -} - -virStorageBackendVolOptionsPtr -virStorageBackendVolOptionsForType(int type) { - virStorageBackendPtr backend = virStorageBackendForType(type); - if (backend == NULL) - return NULL; - return &backend->volOptions; -} - - -int -virStorageBackendFromString(const char *type) { - if (STREQ(type, "dir")) - return VIR_STORAGE_POOL_DIR; -#if WITH_STORAGE_FS - if (STREQ(type, "fs")) - return VIR_STORAGE_POOL_FS; - if (STREQ(type, "netfs")) - return VIR_STORAGE_POOL_NETFS; -#endif -#if WITH_STORAGE_LVM - if (STREQ(type, "logical")) - return VIR_STORAGE_POOL_LOGICAL; -#endif -#if WITH_STORAGE_ISCSI - if (STREQ(type, "iscsi")) - return VIR_STORAGE_POOL_ISCSI; -#endif -#if WITH_STORAGE_DISK - if (STREQ(type, "disk")) - return VIR_STORAGE_POOL_DISK; -#endif - - virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, - _("unknown storage backend type %s"), type); - return -1; -} - -const char * -virStorageBackendToString(int type) { - switch (type) { - case VIR_STORAGE_POOL_DIR: - return "dir"; -#if WITH_STORAGE_FS - case VIR_STORAGE_POOL_FS: - return "fs"; - case VIR_STORAGE_POOL_NETFS: - return "netfs"; -#endif -#if WITH_STORAGE_LVM - case VIR_STORAGE_POOL_LOGICAL: - return "logical"; -#endif -#if WITH_STORAGE_ISCSI - case VIR_STORAGE_POOL_ISCSI: - return "iscsi"; -#endif -#if WITH_STORAGE_DISK - case VIR_STORAGE_POOL_DISK: - return "disk"; -#endif - } - - virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, - _("unknown storage backend type %d"), type); return NULL; } @@ -197,6 +119,13 @@ return ret; } + +struct diskType { + int part_table_type; + unsigned short offset; + unsigned short length; + unsigned long long magic; +}; static struct diskType const disk_types[] = { { VIR_STORAGE_POOL_DISK_LVM2, 0x218, 8, 0x31303020324D564CULL }, @@ -367,6 +296,12 @@ if (pool->def->target.path == NULL || STREQ(pool->def->target.path, "/dev") || STREQ(pool->def->target.path, "/dev/")) + goto ret_strdup; + + /* Skip whole thing for a pool which isn't in /dev + * so we don't mess will filesystem/dir based pools + */ + if (!STRPREFIX(pool->def->target.path, "/dev")) goto ret_strdup; /* The pool is pointing somewhere like /dev/disk/by-path diff -r 19c9bab70d15 src/storage_backend.h --- a/src/storage_backend.h Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend.h Wed Nov 12 21:05:13 2008 +0000 @@ -24,67 +24,8 @@ #ifndef __VIR_STORAGE_BACKEND_H__ #define __VIR_STORAGE_BACKEND_H__ -#include <libvirt/libvirt.h> +#include "internal.h" #include "storage_conf.h" -#include "util.h" - - -typedef const char *(*virStorageVolFormatToString)(int format); -typedef int (*virStorageVolFormatFromString)(const char *format); - -typedef const char *(*virStoragePoolFormatToString)(int format); -typedef int (*virStoragePoolFormatFromString)(const char *format); - -typedef struct _virStorageBackendVolOptions virStorageBackendVolOptions; -typedef virStorageBackendVolOptions *virStorageBackendVolOptionsPtr; -struct _virStorageBackendVolOptions { - virStorageVolFormatToString formatToString; - virStorageVolFormatFromString formatFromString; -}; - - -/* Flags to indicate mandatory components in the pool source */ -enum { - VIR_STORAGE_BACKEND_POOL_SOURCE_HOST = (1<<0), - VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE = (1<<1), - VIR_STORAGE_BACKEND_POOL_SOURCE_DIR = (1<<2), - VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER = (1<<3), - VIR_STORAGE_BACKEND_POOL_SOURCE_NAME = (1<<4), - VIR_STORAGE_BACKEND_POOL_STABLE_PATH = (1<<5), -}; - -enum partTableType { - VIR_STORAGE_POOL_DISK_UNKNOWN = 0, - VIR_STORAGE_POOL_DISK_DOS = 1, - VIR_STORAGE_POOL_DISK_DVH, - VIR_STORAGE_POOL_DISK_GPT, - VIR_STORAGE_POOL_DISK_MAC, - VIR_STORAGE_POOL_DISK_BSD, - VIR_STORAGE_POOL_DISK_PC98, - VIR_STORAGE_POOL_DISK_SUN, - VIR_STORAGE_POOL_DISK_LVM2, - VIR_STORAGE_POOL_DISK_LAST, -}; - -struct diskType { - enum partTableType part_table_type; - unsigned short offset; - unsigned short length; - unsigned long long magic; -}; -VIR_ENUM_DECL(virStorageBackendPartTable); - -typedef struct _virStorageBackendPoolOptions virStorageBackendPoolOptions; -typedef virStorageBackendPoolOptions *virStorageBackendPoolOptionsPtr; -struct _virStorageBackendPoolOptions { - int flags; - int defaultFormat; - virStoragePoolFormatToString formatToString; - virStoragePoolFormatFromString formatFromString; -}; - -#define SOURCES_START_TAG "<sources>" -#define SOURCES_END_TAG "</sources>" typedef char * (*virStorageBackendFindPoolSources)(virConnectPtr conn, const char *srcSpec, unsigned int flags); typedef int (*virStorageBackendStartPool)(virConnectPtr conn, virStoragePoolObjPtr pool); @@ -114,19 +55,10 @@ virStorageBackendCreateVol createVol; virStorageBackendRefreshVol refreshVol; virStorageBackendDeleteVol deleteVol; - - virStorageBackendPoolOptions poolOptions; - virStorageBackendVolOptions volOptions; - - int volType; }; +virStorageBackendPtr virStorageBackendForType(int type); -virStorageBackendPtr virStorageBackendForType(int type); -virStorageBackendPoolOptionsPtr virStorageBackendPoolOptionsForType(int type); -virStorageBackendVolOptionsPtr virStorageBackendVolOptionsForType(int type); -int virStorageBackendFromString(const char *type); -const char *virStorageBackendToString(int type); int virStorageBackendUpdateVolInfo(virConnectPtr conn, virStorageVolDefPtr vol, diff -r 19c9bab70d15 src/storage_backend_disk.c --- a/src/storage_backend_disk.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_disk.c Wed Nov 12 21:05:13 2008 +0000 @@ -24,40 +24,13 @@ #include <config.h> #include <string.h> #include <unistd.h> +#include <stdio.h> #include "virterror_internal.h" #include "logging.h" #include "storage_backend_disk.h" #include "util.h" #include "memory.h" - -/* - * XXX these are basically partition types. - * - * fdisk has a bazillion partition ID types - * parted has practically none, and splits the - * info across 3 different attributes. - * - * So this is a semi-generic set - */ -enum { - VIR_STORAGE_VOL_DISK_NONE = 0, - VIR_STORAGE_VOL_DISK_LINUX, - VIR_STORAGE_VOL_DISK_FAT16, - VIR_STORAGE_VOL_DISK_FAT32, - VIR_STORAGE_VOL_DISK_LINUX_SWAP, - VIR_STORAGE_VOL_DISK_LINUX_LVM, - VIR_STORAGE_VOL_DISK_LINUX_RAID, - VIR_STORAGE_VOL_DISK_EXTENDED, - VIR_STORAGE_VOL_DISK_LAST, -}; -VIR_ENUM_DECL(virStorageBackendDiskVol); -VIR_ENUM_IMPL(virStorageBackendDiskVol, - VIR_STORAGE_VOL_DISK_LAST, - "none", "linux", "fat16", - "fat32", "linux-swap", - "linux-lvm", "linux-raid", - "extended"); #define PARTHELPER BINDIR "/libvirt_parthelper" @@ -154,6 +127,8 @@ if (virStorageBackendUpdateVolInfo(conn, vol, 1) < 0) return -1; + vol->type = VIR_STORAGE_VOL_BLOCK; + /* The above gets allocation wrong for * extended partitions, so overwrite it */ vol->allocation = vol->capacity = @@ -306,7 +281,7 @@ "mklabel", "--script", ((pool->def->source.format == VIR_STORAGE_POOL_DISK_DOS) ? "msdos" : - virStorageBackendPartTableTypeToString(pool->def->source.format)), + virStoragePoolFormatDiskTypeToString(pool->def->source.format)), NULL, }; @@ -445,18 +420,4 @@ .createVol = virStorageBackendDiskCreateVol, .deleteVol = virStorageBackendDiskDeleteVol, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE| - VIR_STORAGE_BACKEND_POOL_STABLE_PATH), - .defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN, - .formatFromString = virStorageBackendPartTableTypeFromString, - .formatToString = virStorageBackendPartTableTypeToString, - }, - .volOptions = { - .formatFromString = virStorageBackendDiskVolTypeFromString, - .formatToString = virStorageBackendDiskVolTypeToString, - }, - - .volType = VIR_STORAGE_VOL_BLOCK, }; diff -r 19c9bab70d15 src/storage_backend_fs.c --- a/src/storage_backend_fs.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_fs.c Wed Nov 12 21:05:13 2008 +0000 @@ -47,59 +47,6 @@ #include "memory.h" #include "xml.h" -enum { - VIR_STORAGE_POOL_FS_AUTO = 0, - VIR_STORAGE_POOL_FS_EXT2, - VIR_STORAGE_POOL_FS_EXT3, - VIR_STORAGE_POOL_FS_EXT4, - VIR_STORAGE_POOL_FS_UFS, - VIR_STORAGE_POOL_FS_ISO, - VIR_STORAGE_POOL_FS_UDF, - VIR_STORAGE_POOL_FS_GFS, - VIR_STORAGE_POOL_FS_GFS2, - VIR_STORAGE_POOL_FS_VFAT, - VIR_STORAGE_POOL_FS_HFSPLUS, - VIR_STORAGE_POOL_FS_XFS, - VIR_STORAGE_POOL_FS_LAST, -}; -VIR_ENUM_DECL(virStorageBackendFileSystemPool); -VIR_ENUM_IMPL(virStorageBackendFileSystemPool, - VIR_STORAGE_POOL_FS_LAST, - "auto", "ext2", "ext3", - "ext4", "ufs", "iso9660", "udf", - "gfs", "gfs2", "vfat", "hfs+", "xfs"); - -enum { - VIR_STORAGE_POOL_NETFS_AUTO = 0, - VIR_STORAGE_POOL_NETFS_NFS, - VIR_STORAGE_POOL_NETFS_LAST, -}; -VIR_ENUM_DECL(virStorageBackendFileSystemNetPool); -VIR_ENUM_IMPL(virStorageBackendFileSystemNetPool, - VIR_STORAGE_POOL_NETFS_LAST, - "auto", "nfs"); - - -enum { - VIR_STORAGE_VOL_RAW = 0, - VIR_STORAGE_VOL_DIR, - VIR_STORAGE_VOL_BOCHS, - VIR_STORAGE_VOL_CLOOP, - VIR_STORAGE_VOL_COW, - VIR_STORAGE_VOL_DMG, - VIR_STORAGE_VOL_ISO, - VIR_STORAGE_VOL_QCOW, - VIR_STORAGE_VOL_QCOW2, - VIR_STORAGE_VOL_VMDK, - VIR_STORAGE_VOL_VPC, - VIR_STORAGE_VOL_LAST, -}; -VIR_ENUM_DECL(virStorageBackendFileSystemVol); -VIR_ENUM_IMPL(virStorageBackendFileSystemVol, - VIR_STORAGE_VOL_LAST, - "raw", "dir", "bochs", - "cloop", "cow", "dmg", "iso", - "qcow", "qcow2", "vmdk", "vpc"); /* Either 'magic' or 'extension' *must* be provided */ struct FileTypeInfo { @@ -130,45 +77,45 @@ __LITTLE_ENDIAN, -1, 0, -1, 0, 0 }, */ /* Cow */ - { VIR_STORAGE_VOL_COW, "OOOM", NULL, + { VIR_STORAGE_VOL_FILE_COW, "OOOM", NULL, __BIG_ENDIAN, 4, 2, 4+4+1024+4, 8, 1 }, /* DMG */ /* XXX QEMU says there's no magic for dmg, but we should check... */ - { VIR_STORAGE_VOL_DMG, NULL, ".dmg", + { VIR_STORAGE_VOL_FILE_DMG, NULL, ".dmg", 0, -1, 0, -1, 0, 0 }, /* XXX there's probably some magic for iso we can validate too... */ - { VIR_STORAGE_VOL_ISO, NULL, ".iso", + { VIR_STORAGE_VOL_FILE_ISO, NULL, ".iso", 0, -1, 0, -1, 0, 0 }, /* Parallels */ /* XXX Untested - { VIR_STORAGE_VOL_PARALLELS, "WithoutFreeSpace", NULL, + { VIR_STORAGE_VOL_FILE_PARALLELS, "WithoutFreeSpace", NULL, __LITTLE_ENDIAN, 16, 2, 16+4+4+4+4, 4, 512 }, */ /* QCow */ - { VIR_STORAGE_VOL_QCOW, "QFI", NULL, + { VIR_STORAGE_VOL_FILE_QCOW, "QFI", NULL, __BIG_ENDIAN, 4, 1, 4+4+8+4+4, 8, 1 }, /* QCow 2 */ - { VIR_STORAGE_VOL_QCOW2, "QFI", NULL, + { VIR_STORAGE_VOL_FILE_QCOW2, "QFI", NULL, __BIG_ENDIAN, 4, 2, 4+4+8+4+4, 8, 1 }, /* VMDK 3 */ /* XXX Untested - { VIR_STORAGE_VOL_VMDK, "COWD", NULL, + { VIR_STORAGE_VOL_FILE_VMDK, "COWD", NULL, __LITTLE_ENDIAN, 4, 1, 4+4+4, 4, 512 }, */ /* VMDK 4 */ - { VIR_STORAGE_VOL_VMDK, "KDMV", NULL, + { VIR_STORAGE_VOL_FILE_VMDK, "KDMV", NULL, __LITTLE_ENDIAN, 4, 1, 4+4+4, 8, 512 }, /* Connectix / VirtualPC */ /* XXX Untested - { VIR_STORAGE_VOL_VPC, "conectix", NULL, + { VIR_STORAGE_VOL_FILE_VPC, "conectix", NULL, __BIG_ENDIAN, -1, 0, -1, 0, 0}, */ @@ -288,7 +235,7 @@ } /* All fails, so call it a raw file */ - def->target.format = VIR_STORAGE_VOL_RAW; + def->target.format = VIR_STORAGE_VOL_FILE_RAW; return 0; } @@ -486,8 +433,8 @@ MOUNT, "-t", pool->def->type == VIR_STORAGE_POOL_FS ? - virStorageBackendFileSystemPoolTypeToString(pool->def->source.format) : - virStorageBackendFileSystemNetPoolTypeToString(pool->def->source.format), + virStoragePoolFormatFileSystemTypeToString(pool->def->source.format) : + virStoragePoolFormatFileSystemNetTypeToString(pool->def->source.format), NULL, /* Fill in shortly - careful not to add extra fields before this */ pool->def->target.path, @@ -689,7 +636,8 @@ if ((vol->name = strdup(ent->d_name)) == NULL) goto no_memory; - vol->target.format = VIR_STORAGE_VOL_RAW; /* Real value is filled in during probe */ + vol->type = VIR_STORAGE_VOL_FILE; + vol->target.format = VIR_STORAGE_VOL_FILE_RAW; /* Real value is filled in during probe */ if (VIR_ALLOC_N(vol->target.path, strlen(pool->def->target.path) + 1 + strlen(vol->name) + 1) < 0) goto no_memory; @@ -815,6 +763,7 @@ virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("target")); return -1; } + vol->type = VIR_STORAGE_VOL_FILE; strcpy(vol->target.path, pool->def->target.path); strcat(vol->target.path, "/"); strcat(vol->target.path, vol->name); @@ -825,7 +774,7 @@ return -1; } - if (vol->target.format == VIR_STORAGE_VOL_RAW) { + if (vol->target.format == VIR_STORAGE_VOL_FILE_RAW) { if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL, vol->target.perms.mode)) < 0) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, @@ -865,7 +814,7 @@ close(fd); return -1; } - } else if (vol->target.format == VIR_STORAGE_VOL_DIR) { + } else if (vol->target.format == VIR_STORAGE_VOL_FILE_DIR) { if (mkdir(vol->target.path, vol->target.perms.mode) < 0) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("cannot create path '%s': %s"), @@ -885,7 +834,7 @@ char size[100]; const char *imgargv[7]; - if ((type = virStorageBackendFileSystemVolTypeToString(vol->target.format)) == NULL) { + if ((type = virStorageVolFormatFileSystemTypeToString(vol->target.format)) == NULL) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unknown storage vol type %d"), vol->target.format); @@ -923,7 +872,7 @@ char size[100]; const char *imgargv[4]; - if (vol->target.format != VIR_STORAGE_VOL_QCOW2) { + if (vol->target.format != VIR_STORAGE_VOL_FILE_QCOW2) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, _("unsupported storage vol type %d"), vol->target.format); @@ -1040,12 +989,6 @@ .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, - - .volOptions = { - .formatFromString = virStorageBackendFileSystemVolTypeFromString, - .formatToString = virStorageBackendFileSystemVolTypeToString, - }, - .volType = VIR_STORAGE_VOL_FILE, }; #if WITH_STORAGE_FS @@ -1060,17 +1003,6 @@ .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE), - .formatFromString = virStorageBackendFileSystemPoolTypeFromString, - .formatToString = virStorageBackendFileSystemPoolTypeToString, - }, - .volOptions = { - .formatFromString = virStorageBackendFileSystemVolTypeFromString, - .formatToString = virStorageBackendFileSystemVolTypeToString, - }, - .volType = VIR_STORAGE_VOL_FILE, }; virStorageBackend virStorageBackendNetFileSystem = { .type = VIR_STORAGE_POOL_NETFS, @@ -1084,18 +1016,5 @@ .createVol = virStorageBackendFileSystemVolCreate, .refreshVol = virStorageBackendFileSystemVolRefresh, .deleteVol = virStorageBackendFileSystemVolDelete, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_HOST | - VIR_STORAGE_BACKEND_POOL_SOURCE_DIR), - .defaultFormat = VIR_STORAGE_POOL_FS_AUTO, - .formatFromString = virStorageBackendFileSystemNetPoolTypeFromString, - .formatToString = virStorageBackendFileSystemNetPoolTypeToString, - }, - .volOptions = { - .formatFromString = virStorageBackendFileSystemVolTypeFromString, - .formatToString = virStorageBackendFileSystemVolTypeToString, - }, - .volType = VIR_STORAGE_VOL_FILE, }; #endif /* WITH_STORAGE_FS */ diff -r 19c9bab70d15 src/storage_backend_iscsi.c --- a/src/storage_backend_iscsi.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_iscsi.c Wed Nov 12 21:05:13 2008 +0000 @@ -177,6 +177,8 @@ virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("volume")); goto cleanup; } + + vol->type = VIR_STORAGE_VOL_BLOCK; if (asprintf(&(vol->name), "lun-%d", lun) < 0) { virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("name")); @@ -641,15 +643,4 @@ .startPool = virStorageBackendISCSIStartPool, .refreshPool = virStorageBackendISCSIRefreshPool, .stopPool = virStorageBackendISCSIStopPool, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_HOST | - VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE | - VIR_STORAGE_BACKEND_POOL_STABLE_PATH) - }, - - .volType = VIR_STORAGE_VOL_BLOCK, - .volOptions = { - .formatToString = virStorageBackendPartTableTypeToString, - } }; diff -r 19c9bab70d15 src/storage_backend_logical.c --- a/src/storage_backend_logical.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_backend_logical.c Wed Nov 12 21:05:13 2008 +0000 @@ -39,15 +39,6 @@ #define PV_BLANK_SECTOR_SIZE 512 -enum { - VIR_STORAGE_POOL_LOGICAL_UNKNOWN = 0, - VIR_STORAGE_POOL_LOGICAL_LVM2 = 1, - VIR_STORAGE_POOL_LOGICAL_LAST, -}; -VIR_ENUM_DECL(virStorageBackendLogicalPool); -VIR_ENUM_IMPL(virStorageBackendLogicalPool, - VIR_STORAGE_POOL_LOGICAL_LAST, - "unknown", "lvm2"); static int virStorageBackendLogicalSetActive(virConnectPtr conn, @@ -94,6 +85,8 @@ virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("volume")); return -1; } + + vol->type = VIR_STORAGE_VOL_BLOCK; if ((vol->name = strdup(groups[0])) == NULL) { virStorageReportError(conn, VIR_ERR_NO_MEMORY, "%s", _("volume")); @@ -574,6 +567,8 @@ snprintf(size, sizeof(size)-1, "%lluK", vol->capacity/1024); size[sizeof(size)-1] = '\0'; + vol->type = VIR_STORAGE_VOL_BLOCK; + if (vol->target.path != NULL) { /* A target path passed to CreateVol has no meaning */ VIR_FREE(vol->target.path); @@ -666,14 +661,4 @@ .deletePool = virStorageBackendLogicalDeletePool, .createVol = virStorageBackendLogicalCreateVol, .deleteVol = virStorageBackendLogicalDeleteVol, - - .poolOptions = { - .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_NAME | - VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE), - .defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2, - .formatFromString = virStorageBackendLogicalPoolTypeFromString, - .formatToString = virStorageBackendLogicalPoolTypeToString, - }, - - .volType = VIR_STORAGE_VOL_BLOCK, }; diff -r 19c9bab70d15 src/storage_conf.c --- a/src/storage_conf.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_conf.c Wed Nov 12 21:05:13 2008 +0000 @@ -36,7 +36,7 @@ #include "virterror_internal.h" #include "datatypes.h" #include "storage_conf.h" -#include "storage_backend.h" + #include "xml.h" #include "uuid.h" #include "buf.h" @@ -44,6 +44,181 @@ #include "memory.h" #define virStorageLog(msg...) fprintf(stderr, msg) + +VIR_ENUM_IMPL(virStoragePool, + VIR_STORAGE_POOL_LAST, + "dir", "fs", "netfs", + "logical", "disk", "iscsi", + "scsi"); + +VIR_ENUM_IMPL(virStoragePoolFormatFileSystem, + VIR_STORAGE_POOL_FS_LAST, + "auto", "ext2", "ext3", + "ext4", "ufs", "iso9660", "udf", + "gfs", "gfs2", "vfat", "hfs+", "xfs"); + +VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet, + VIR_STORAGE_POOL_NETFS_LAST, + "auto", "nfs"); + +VIR_ENUM_IMPL(virStoragePoolFormatDisk, + VIR_STORAGE_POOL_DISK_LAST, + "unknown", "dos", "dvh", "gpt", + "mac", "bsd", "pc98", "sun", "lvm2"); + +VIR_ENUM_IMPL(virStoragePoolFormatLogical, + VIR_STORAGE_POOL_LOGICAL_LAST, + "unknown", "lvm2"); + + +VIR_ENUM_IMPL(virStorageVolFormatDisk, + VIR_STORAGE_VOL_DISK_LAST, + "none", "linux", "fat16", + "fat32", "linux-swap", + "linux-lvm", "linux-raid", + "extended"); + +VIR_ENUM_IMPL(virStorageVolFormatFileSystem, + VIR_STORAGE_VOL_FILE_LAST, + "raw", "dir", "bochs", + "cloop", "cow", "dmg", "iso", + "qcow", "qcow2", "vmdk", "vpc"); + + +typedef const char *(*virStorageVolFormatToString)(int format); +typedef int (*virStorageVolFormatFromString)(const char *format); + +typedef const char *(*virStoragePoolFormatToString)(int format); +typedef int (*virStoragePoolFormatFromString)(const char *format); + +typedef struct _virStorageVolOptions virStorageVolOptions; +typedef virStorageVolOptions *virStorageVolOptionsPtr; +struct _virStorageVolOptions { + virStorageVolFormatToString formatToString; + virStorageVolFormatFromString formatFromString; +}; + +/* Flags to indicate mandatory components in the pool source */ +enum { + VIR_STORAGE_POOL_SOURCE_HOST = (1<<0), + VIR_STORAGE_POOL_SOURCE_DEVICE = (1<<1), + VIR_STORAGE_POOL_SOURCE_DIR = (1<<2), + VIR_STORAGE_POOL_SOURCE_ADAPTER = (1<<3), + VIR_STORAGE_POOL_SOURCE_NAME = (1<<4), +}; + + + +typedef struct _virStoragePoolOptions virStoragePoolOptions; +typedef virStoragePoolOptions *virStoragePoolOptionsPtr; +struct _virStoragePoolOptions { + int flags; + int defaultFormat; + virStoragePoolFormatToString formatToString; + virStoragePoolFormatFromString formatFromString; +}; + +typedef struct _virStoragePoolTypeInfo virStoragePoolTypeInfo; +typedef virStoragePoolTypeInfo *virStoragePoolTypeInfoPtr; + +struct _virStoragePoolTypeInfo { + int poolType; + virStoragePoolOptions poolOptions; + virStorageVolOptions volOptions; +}; + +static virStoragePoolTypeInfo poolTypeInfo[] = { + { .poolType = VIR_STORAGE_POOL_LOGICAL, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_NAME | + VIR_STORAGE_POOL_SOURCE_DEVICE), + .defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2, + .formatFromString = virStoragePoolFormatLogicalTypeFromString, + .formatToString = virStoragePoolFormatLogicalTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_DIR, + .volOptions = { + .formatFromString = virStorageVolFormatFileSystemTypeFromString, + .formatToString = virStorageVolFormatFileSystemTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_FS, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE), + .formatFromString = virStoragePoolFormatFileSystemTypeFromString, + .formatToString = virStoragePoolFormatFileSystemTypeToString, + }, + .volOptions = { + .formatFromString = virStorageVolFormatFileSystemTypeFromString, + .formatToString = virStorageVolFormatFileSystemTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_NETFS, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_DIR), + .defaultFormat = VIR_STORAGE_POOL_FS_AUTO, + .formatFromString = virStoragePoolFormatFileSystemNetTypeFromString, + .formatToString = virStoragePoolFormatFileSystemNetTypeToString, + }, + .volOptions = { + .formatFromString = virStorageVolFormatFileSystemTypeFromString, + .formatToString = virStorageVolFormatFileSystemTypeToString, + }, + }, + { .poolType = VIR_STORAGE_POOL_ISCSI, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_HOST | + VIR_STORAGE_POOL_SOURCE_DEVICE), + }, + .volOptions = { + .formatToString = virStoragePoolFormatDiskTypeToString, + } + }, + { .poolType = VIR_STORAGE_POOL_DISK, + .poolOptions = { + .flags = (VIR_STORAGE_POOL_SOURCE_DEVICE), + .defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN, + .formatFromString = virStoragePoolFormatDiskTypeFromString, + .formatToString = virStoragePoolFormatDiskTypeToString, + }, + .volOptions = { + .formatFromString = virStorageVolFormatDiskTypeFromString, + .formatToString = virStorageVolFormatDiskTypeToString, + }, + } +}; + + +static virStoragePoolTypeInfoPtr +virStoragePoolTypeInfoLookup(int type) { + unsigned int i; + for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo) ; i++) + if (poolTypeInfo[i].poolType == type) + return &poolTypeInfo[i]; + + virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR, + _("missing backend for pool type %d"), type); + return NULL; +} + +static virStoragePoolOptionsPtr +virStoragePoolOptionsForPoolType(int type) { + virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type); + if (backend == NULL) + return NULL; + return &backend->poolOptions; +} + +static virStorageVolOptionsPtr +virStorageVolOptionsForPoolType(int type) { + virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type); + if (backend == NULL) + return NULL; + return &backend->volOptions; +} + void virStorageVolDefFree(virStorageVolDefPtr def) { @@ -224,7 +399,7 @@ virStoragePoolDefParseDoc(virConnectPtr conn, xmlXPathContextPtr ctxt, xmlNodePtr root) { - virStorageBackendPoolOptionsPtr options; + virStoragePoolOptionsPtr options; virStoragePoolDefPtr ret; xmlChar *type = NULL; char *uuid = NULL; @@ -238,23 +413,27 @@ if (STRNEQ((const char *)root->name, "pool")) { virStorageReportError(conn, VIR_ERR_XML_ERROR, - "%s", _("unknown root elementi for storage pool")); + "%s", _("unknown root element for storage pool")); goto cleanup; } type = xmlGetProp(root, BAD_CAST "type"); - if ((ret->type = virStorageBackendFromString((const char *)type)) < 0) + if ((ret->type = virStoragePoolTypeFromString((const char *)type)) < 0) { + virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, + _("unknown storage pool type %s"), (const char*)type); goto cleanup; + } + xmlFree(type); type = NULL; - if ((options = virStorageBackendPoolOptionsForType(ret->type)) == NULL) { + if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) { goto cleanup; } ret->name = virXPathString(conn, "string(/pool/name)", ctxt); if (ret->name == NULL && - options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_NAME) + options->flags & VIR_STORAGE_POOL_SOURCE_NAME) ret->name = virXPathString(conn, "string(/pool/source/name)", ctxt); if (ret->name == NULL) { virStorageReportError(conn, VIR_ERR_XML_ERROR, @@ -294,14 +473,14 @@ VIR_FREE(format); } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) { if ((ret->source.host.name = virXPathString(conn, "string(/pool/source/host/@name)", ctxt)) == NULL) { virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", _("missing storage pool source host name")); goto cleanup; } } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) { xmlNodePtr *nodeset = NULL; int nsource, i; @@ -328,14 +507,14 @@ VIR_FREE(nodeset); ret->source.ndevice = nsource; } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) { if ((ret->source.dir = virXPathString(conn, "string(/pool/source/dir/@path)", ctxt)) == NULL) { virStorageReportError(conn, VIR_ERR_XML_ERROR, "%s", _("missing storage pool source path")); goto cleanup; } } - if (options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_NAME) { + if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) { ret->source.name = virXPathString(conn, "string(/pool/source/name)", ctxt); if (ret->source.name == NULL) { @@ -471,17 +650,17 @@ static int virStoragePoolSourceFormat(virConnectPtr conn, virBufferPtr buf, - virStorageBackendPoolOptionsPtr options, + virStoragePoolOptionsPtr options, virStoragePoolSourcePtr src) { int i, j; virBufferAddLit(buf," <source>\n"); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_HOST) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->host.name) virBufferVSprintf(buf," <host name='%s'/>\n", src->host.name); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) && src->ndevice) { for (i = 0 ; i < src->ndevice ; i++) { if (src->devices[i].nfreeExtent) { @@ -499,13 +678,13 @@ src->devices[i].path); } } - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_DIR) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) && src->dir) virBufferVSprintf(buf," <dir path='%s'/>\n", src->dir); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_ADAPTER) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) && src->adapter) virBufferVSprintf(buf," <adapter name='%s'/>\n", src->adapter); - if ((options->flags & VIR_STORAGE_BACKEND_POOL_SOURCE_NAME) && + if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) && src->name) virBufferVSprintf(buf," <name>%s</name>\n", src->name); @@ -534,16 +713,16 @@ char * virStoragePoolDefFormat(virConnectPtr conn, virStoragePoolDefPtr def) { - virStorageBackendPoolOptionsPtr options; + virStoragePoolOptionsPtr options; virBuffer buf = VIR_BUFFER_INITIALIZER; const char *type; char uuid[VIR_UUID_STRING_BUFLEN]; - options = virStorageBackendPoolOptionsForType(def->type); + options = virStoragePoolOptionsForPoolType(def->type); if (options == NULL) return NULL; - type = virStorageBackendToString(def->type); + type = virStoragePoolTypeToString(def->type); if (!type) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("unexpected pool type")); @@ -725,12 +904,12 @@ xmlXPathContextPtr ctxt, xmlNodePtr root) { virStorageVolDefPtr ret; - virStorageBackendVolOptionsPtr options; + virStorageVolOptionsPtr options; char *allocation = NULL; char *capacity = NULL; char *unit = NULL; - options = virStorageBackendVolOptionsForType(pool->type); + options = virStorageVolOptionsForPoolType(pool->type); if (options == NULL) return NULL; @@ -870,11 +1049,11 @@ virStorageVolDefFormat(virConnectPtr conn, virStoragePoolDefPtr pool, virStorageVolDefPtr def) { - virStorageBackendVolOptionsPtr options; + virStorageVolOptionsPtr options; virBuffer buf = VIR_BUFFER_INITIALIZER; char *tmp; - options = virStorageBackendVolOptionsForType(pool->type); + options = virStorageVolOptionsForPoolType(pool->type); if (options == NULL) return NULL; @@ -1283,16 +1462,16 @@ char *virStoragePoolSourceListFormat(virConnectPtr conn, virStoragePoolSourceListPtr def) { - virStorageBackendPoolOptionsPtr options; + virStoragePoolOptionsPtr options; virBuffer buf = VIR_BUFFER_INITIALIZER; const char *type; int i; - options = virStorageBackendPoolOptionsForType(def->type); + options = virStoragePoolOptionsForPoolType(def->type); if (options == NULL) return NULL; - type = virStorageBackendToString(def->type); + type = virStoragePoolTypeToString(def->type); if (!type) { virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s", _("unexpected pool type")); diff -r 19c9bab70d15 src/storage_conf.h --- a/src/storage_conf.h Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_conf.h Wed Nov 12 21:05:13 2008 +0000 @@ -24,11 +24,8 @@ #ifndef __VIR_STORAGE_CONF_H__ #define __VIR_STORAGE_CONF_H__ -#include <libxml/parser.h> -#include <libxml/tree.h> -#include <libxml/xpath.h> - #include "internal.h" +#include "util.h" /* Shared structs */ @@ -84,6 +81,7 @@ struct _virStorageVolDef { char *name; char *key; + int type; /* virStorageVolType enum */ unsigned long long allocation; unsigned long long capacity; @@ -104,14 +102,18 @@ /* Storage pools */ enum virStoragePoolType { - VIR_STORAGE_POOL_DIR = 1, /* Local directory */ + VIR_STORAGE_POOL_DIR, /* Local directory */ VIR_STORAGE_POOL_FS, /* Local filesystem */ VIR_STORAGE_POOL_NETFS, /* Networked filesystem - eg NFS, GFS, etc */ VIR_STORAGE_POOL_LOGICAL, /* Logical volume groups / volumes */ VIR_STORAGE_POOL_DISK, /* Disk partitions */ VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */ VIR_STORAGE_POOL_SCSI, /* SCSI HBA */ + + VIR_STORAGE_POOL_LAST, }; + +VIR_ENUM_DECL(virStoragePool); enum virStoragePoolAuthType { @@ -259,6 +261,7 @@ unsigned int nsources; virStoragePoolSourcePtr sources; }; + static inline int virStoragePoolObjIsActive(virStoragePoolObjPtr pool) { return pool->active; @@ -322,4 +325,93 @@ char *virStoragePoolSourceListFormat(virConnectPtr conn, virStoragePoolSourceListPtr def); + + +enum virStoragePoolFormatFileSystem { + VIR_STORAGE_POOL_FS_AUTO = 0, + VIR_STORAGE_POOL_FS_EXT2, + VIR_STORAGE_POOL_FS_EXT3, + VIR_STORAGE_POOL_FS_EXT4, + VIR_STORAGE_POOL_FS_UFS, + VIR_STORAGE_POOL_FS_ISO, + VIR_STORAGE_POOL_FS_UDF, + VIR_STORAGE_POOL_FS_GFS, + VIR_STORAGE_POOL_FS_GFS2, + VIR_STORAGE_POOL_FS_VFAT, + VIR_STORAGE_POOL_FS_HFSPLUS, + VIR_STORAGE_POOL_FS_XFS, + VIR_STORAGE_POOL_FS_LAST, +}; +VIR_ENUM_DECL(virStoragePoolFormatFileSystem); + +enum virStoragePoolFormatFileSystemNet { + VIR_STORAGE_POOL_NETFS_AUTO = 0, + VIR_STORAGE_POOL_NETFS_NFS, + VIR_STORAGE_POOL_NETFS_LAST, +}; +VIR_ENUM_DECL(virStoragePoolFormatFileSystemNet); + +enum virStoragePoolFormatDisk { + VIR_STORAGE_POOL_DISK_UNKNOWN = 0, + VIR_STORAGE_POOL_DISK_DOS = 1, + VIR_STORAGE_POOL_DISK_DVH, + VIR_STORAGE_POOL_DISK_GPT, + VIR_STORAGE_POOL_DISK_MAC, + VIR_STORAGE_POOL_DISK_BSD, + VIR_STORAGE_POOL_DISK_PC98, + VIR_STORAGE_POOL_DISK_SUN, + VIR_STORAGE_POOL_DISK_LVM2, + VIR_STORAGE_POOL_DISK_LAST, +}; + +VIR_ENUM_DECL(virStoragePoolFormatDisk); + +enum virStoragePoolFormatLogical { + VIR_STORAGE_POOL_LOGICAL_UNKNOWN = 0, + VIR_STORAGE_POOL_LOGICAL_LVM2 = 1, + VIR_STORAGE_POOL_LOGICAL_LAST, +}; +VIR_ENUM_DECL(virStoragePoolFormatLogical); + + +enum virStorageVolFormatFileSystem { + VIR_STORAGE_VOL_FILE_RAW = 0, + VIR_STORAGE_VOL_FILE_DIR, + VIR_STORAGE_VOL_FILE_BOCHS, + VIR_STORAGE_VOL_FILE_CLOOP, + VIR_STORAGE_VOL_FILE_COW, + VIR_STORAGE_VOL_FILE_DMG, + VIR_STORAGE_VOL_FILE_ISO, + VIR_STORAGE_VOL_FILE_QCOW, + VIR_STORAGE_VOL_FILE_QCOW2, + VIR_STORAGE_VOL_FILE_VMDK, + VIR_STORAGE_VOL_FILE_VPC, + VIR_STORAGE_VOL_FILE_LAST, +}; +VIR_ENUM_DECL(virStorageVolFormatFileSystem); + +/* + * XXX these are basically partition types. + * + * fdisk has a bazillion partition ID types + * parted has practically none, and splits the + * info across 3 different attributes. + * + * So this is a semi-generic set + */ +enum virStorageVolFormatDisk { + VIR_STORAGE_VOL_DISK_NONE = 0, + VIR_STORAGE_VOL_DISK_LINUX, + VIR_STORAGE_VOL_DISK_FAT16, + VIR_STORAGE_VOL_DISK_FAT32, + VIR_STORAGE_VOL_DISK_LINUX_SWAP, + VIR_STORAGE_VOL_DISK_LINUX_LVM, + VIR_STORAGE_VOL_DISK_LINUX_RAID, + VIR_STORAGE_VOL_DISK_EXTENDED, + VIR_STORAGE_VOL_DISK_LAST, +}; +VIR_ENUM_DECL(virStorageVolFormatDisk); + + + #endif /* __VIR_STORAGE_CONF_H__ */ diff -r 19c9bab70d15 src/storage_driver.c --- a/src/storage_driver.c Wed Nov 12 16:38:19 2008 +0000 +++ b/src/storage_driver.c Wed Nov 12 21:05:13 2008 +0000 @@ -403,7 +403,7 @@ int backend_type; virStorageBackendPtr backend; - backend_type = virStorageBackendFromString(type); + backend_type = virStoragePoolTypeFromString(type); if (backend_type < 0) return NULL; @@ -968,33 +968,22 @@ for (i = 0 ; i < driver->pools.count ; i++) { if (virStoragePoolObjIsActive(driver->pools.objs[i])) { virStorageVolDefPtr vol; - virStorageBackendPoolOptionsPtr options; + const char *stable_path; - options = virStorageBackendPoolOptionsForType(driver->pools.objs[i]->def->type); - if (options == NULL) - continue; + stable_path = virStorageBackendStablePath(conn, + driver->pools.objs[i], + path); + /* + * virStorageBackendStablePath already does + * virStorageReportError if it fails; we just need to keep + * propagating the return code + */ + if (stable_path == NULL) + return NULL; - if (options->flags & VIR_STORAGE_BACKEND_POOL_STABLE_PATH) { - const char *stable_path; - - stable_path = virStorageBackendStablePath(conn, - driver->pools.objs[i], - path); - /* - * virStorageBackendStablePath already does - * virStorageReportError if it fails; we just need to keep - * propagating the return code - */ - if (stable_path == NULL) - return NULL; - - vol = virStorageVolDefFindByPath(driver->pools.objs[i], - stable_path); - VIR_FREE(stable_path); - } - else - vol = virStorageVolDefFindByPath(driver->pools.objs[i], path); - + vol = virStorageVolDefFindByPath(driver->pools.objs[i], + stable_path); + VIR_FREE(stable_path); if (vol) return virGetStorageVol(conn, @@ -1170,7 +1159,7 @@ return -1; memset(info, 0, sizeof(*info)); - info->type = backend->volType; + info->type = vol->type; info->capacity = vol->capacity; info->allocation = vol->allocation; -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- 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