On Tue, Feb 12, 2008 at 04:37:57AM +0000, Daniel P. Berrange wrote:
This patch implements 3 storage pools in one go. This provides
the base level 'directory' storage pool, where an existing directory
contains files as volumes. This is guarenteed to be available on
any OS since it just uses plain POSIX apis for creation/deletion.
If qemu-img or qcow2-create command line tools are available it
can also create various non-raw fileformats such as QCow2, VMDK.
If the mount/unmount commands are available, the 'fs' and 'netfs'
pools become available. This allow a local disk, or remote filesystem
to be mounted on the local filesystem, and files managed within.
This driver contains code for probing the non-raw file formats to
determine their logical capacity.
b/docs/storage/pool-dir.xml | 6
b/docs/storage/pool-fs.xml | 15
b/docs/storage/pool-netfs.xml | 16
b/docs/storage/vol-cow.xml | 10
b/docs/storage/vol-qcow.xml | 10
b/docs/storage/vol-qcow2.xml | 10
b/docs/storage/vol-raw.xml | 7
b/docs/storage/vol-sparse.xml | 7
b/docs/storage/vol-vmdk.xml | 10
b/src/storage_backend_fs.c | 1123 ++++++++++++++++++++++++++++++++++++++++++
b/src/storage_backend_fs.h | 49 +
configure.in | 52 +
libvirt.spec.in | 24
po/POTFILES.in | 1
src/Makefile.am | 1
src/storage_backend.c | 34 +
16 files changed, 1375 insertions(+)
diff -r 686cf593fe28 configure.in
--- a/configure.in Tue Feb 19 17:04:59 2008 -0500
+++ b/configure.in Tue Feb 19 17:22:04 2008 -0500
@@ -551,6 +551,52 @@ AC_SUBST(VIRSH_LIBS)
AC_SUBST(WITH_XEN)
AC_SUBST(LIBVIRT_FEATURES)
+
+
+dnl
+dnl Storage driver checks
+dnl
+
+AC_ARG_WITH(storage-fs,
+[ --with-storage-fs with FileSystem backend for the storage driver
(on)],[],[with_storage_fs=check])
+
+if test "$with_storage_fs" = "yes" -o "$with_storage_fs" =
"check"; then
+ AC_PATH_PROG(MOUNT, [mount], [], [$PATH:/sbin:/usr/sbin])
+ AC_PATH_PROG(UMOUNT, [umount], [], [$PATH:/sbin:/usr/sbin])
+ if test "$with_storage_fs" = "yes" ; then
+ if test -z "$MOUNT" ; then AC_MSG_ERROR(We need mount for FS storage
driver) ; fi
+ if test -z "$UMOUNT" ; then AC_MSG_ERROR(We need mount for FS storage
driver) ; fi
+ else
+ if test -z "$MOUNT" ; then with_storage_fs=no ; fi
+ if test -z "$UMOUNT" ; then with_storage_fs=no ; fi
+
+ if test "$with_storage_fs" = "check" ; then with_storage_fs=yes ;
fi
+ fi
+
+ if test "$with_storage_fs" = "yes" ; then
+ AC_DEFINE_UNQUOTED(WITH_STORAGE_FS, 1, [whether FS backend for storage driver is
enabled])
+ AC_DEFINE_UNQUOTED([MOUNT],["$MOUNT"],
+ [Location or name of the mount program])
+ AC_DEFINE_UNQUOTED([UMOUNT],["$UMOUNT"],
+ [Location or name of the mount program])
+ fi
+fi
+AM_CONDITIONAL(WITH_STORAGE_FS, [test "$with_storage_fs" = "yes"])
+
+AC_PATH_PROG(QEMU_IMG, [qemu-img], [], [$PATH:/sbin:/usr/sbin:/bin:/usr/bin])
+if test -n "$QEMU_IMG" ; then
+ AC_DEFINE_UNQUOTED(HAVE_QEMU_IMG, 1, [whether qemu-img is available for non-raw
files])
+ AC_DEFINE_UNQUOTED([QEMU_IMG],["$QEMU_IMG"],
+ [Location or name of the qemu-img program])
+fi
+
+AC_PATH_PROG(QCOW_CREATE, [qcow-create], [], [$PATH:/sbin:/usr/sbin:/bin:/usr/bin])
+if test -n "$QCOW_CREATE" ; then
+ AC_DEFINE_UNQUOTED(HAVE_QCOW_CREATE, 1, [whether qcow-create is available for non-raw
files])
+ AC_DEFINE_UNQUOTED([QCOW_CREATE],["$QCOW_CREATE"],
+ [Location or name of the qcow-create program])
+fi
+
dnl
dnl check for python
@@ -760,6 +806,12 @@ AC_MSG_NOTICE([ Remote: $with_remote])
AC_MSG_NOTICE([ Remote: $with_remote])
AC_MSG_NOTICE([Libvirtd: $with_libvirtd])
AC_MSG_NOTICE([])
+AC_MSG_NOTICE([Storage Drivers])
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([ Dir: yes])
+AC_MSG_NOTICE([ FS: $with_storage_fs])
+AC_MSG_NOTICE([ NetFS: $with_storage_fs])
+AC_MSG_NOTICE([])
AC_MSG_NOTICE([Libraries])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([ libxml: $LIBXML_CFLAGS $LIBXML_LIBS])
diff -r 686cf593fe28 docs/storage/pool-dir.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-dir.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,6 @@
+<pool type="dir">
+ <name>virtimages</name>
+ <target>
+ <path>/var/lib/virt/images</path>
+ </target>
+</pool>
diff -r 686cf593fe28 docs/storage/pool-fs.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-fs.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,15 @@
+<pool type="fs">
+ <name>virtimages</name>
+ <source>
+ <device path="/dev/VolGroup00/VirtImages"/>
+ </source>
+ <target>
+ <path>/var/lib/virt/images</path>
+ <permissions>
+ <mode>0700</mode>
+ <owner>0</owner>
+ <group>0</group>
+ <label>system_u:object_r:xen_image_t:s0</label>
+ </permissions>
+ </target>
+</pool>
diff -r 686cf593fe28 docs/storage/pool-netfs.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/pool-netfs.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,16 @@
+<pool type="netfs">
+ <name>virtimages</name>
+ <source>
+ <host name="nfs.example.com"/>
+ <directory path="/var/lib/virt/images"/>
+ </source>
+ <target>
+ <path>/var/lib/virt/images</path>
+ <permissions>
+ <mode>0700</mode>
+ <owner>0</owner>
+ <group>0</group>
+ <label>system_u:object_r:xen_image_t:s0</label>
+ </permissions>
+ </target>
+</pool>
diff -r 686cf593fe28 docs/storage/vol-cow.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-cow.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+ <name>cow.img</name>
+ <storage>
+ <allocation>0</allocation>
+ <capacity unit="T">1</capacity>
+ </storage>
+ <target>
+ <format type="cow"/>
+ </target>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-qcow.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-qcow.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+ <name>qcow.img</name>
+ <storage>
+ <allocation>0</allocation>
+ <capacity unit="T">1</capacity>
+ </storage>
+ <target>
+ <format type="qcow"/>
+ </target>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-qcow2.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-qcow2.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+ <name>qcow2.img</name>
+ <storage>
+ <allocation>0</allocation>
+ <capacity unit="T">1</capacity>
+ </storage>
+ <target>
+ <format type="qcow2"/>
+ </target>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-raw.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-raw.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,7 @@
+<volume type="file">
+ <name>raw.img</name>
+ <storage>
+ <allocation unit="M">10</allocation>
+ <capacity unit="M">1000</capacity>
+ </storage>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-sparse.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-sparse.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,7 @@
+<volume type="file">
+ <name>sparse.img</name>
+ <storage>
+ <allocation>0</allocation>
+ <capacity unit="T">1</capacity>
+ </storage>
+</volume>
diff -r 686cf593fe28 docs/storage/vol-vmdk.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/docs/storage/vol-vmdk.xml Tue Feb 19 17:22:04 2008 -0500
@@ -0,0 +1,10 @@
+<volume type="file">
+ <name>vmdk3.img</name>
+ <storage>
+ <allocation>0</allocation>
+ <capacity unit="T">1</capacity>
+ </storage>
+ <target>
+ <format type="vmdk"/>
+ </target>
+</volume>
diff -r 686cf593fe28 libvirt.spec.in
--- a/libvirt.spec.in Tue Feb 19 17:04:59 2008 -0500
+++ b/libvirt.spec.in Tue Feb 19 17:22:04 2008 -0500
@@ -6,6 +6,12 @@
%else
%define with_polkit 0
%define with_proxy yes
+%endif
+
+%if "%{fedora}"
+%define with_qemu 1
+%else
+%define with_qemu 0
%endif
Summary: Library providing a simple API virtualization
@@ -34,6 +40,15 @@ Requires: cyrus-sasl-md5
%if %{with_polkit}
Requires: PolicyKit >= 0.6
%endif
+# For mount/umount in FS driver
+BuildRequires: util-linux
+%if %{with_qemu}
+# From QEMU RPMs
+Requires: /usr/bin/qemu-img
+%else
+# From Xen RPMs
+Requires: /usr/sbin/qcow-create
+%endif
BuildRequires: xen-devel
BuildRequires: libxml2-devel
BuildRequires: readline-devel
@@ -48,6 +63,15 @@ BuildRequires: cyrus-sasl-devel
BuildRequires: cyrus-sasl-devel
%if %{with_polkit}
BuildRequires: PolicyKit-devel >= 0.6
+%endif
+# For mount/umount in FS driver
+BuildRequires: util-linux
+%if %{with_qemu}
+# From QEMU RPMs
+BuildRequires: /usr/bin/qemu-img
+%else
+# From Xen RPMs
+BuildRequires: /usr/sbin/qcow-create
%endif
Obsoletes: libvir
ExclusiveArch: i386 x86_64 ia64
diff -r 686cf593fe28 po/POTFILES.in
--- a/po/POTFILES.in Tue Feb 19 17:04:59 2008 -0500
+++ b/po/POTFILES.in Tue Feb 19 17:22:04 2008 -0500
@@ -11,6 +11,7 @@ src/qemu_driver.c
src/qemu_driver.c
src/remote_internal.c
src/storage_backend.c
+src/storage_backend_fs.c
src/storage_conf.c
src/storage_driver.c
src/sexpr.c
diff -r 686cf593fe28 src/Makefile.am
--- a/src/Makefile.am Tue Feb 19 17:04:59 2008 -0500
+++ b/src/Makefile.am Tue Feb 19 17:22:04 2008 -0500
@@ -62,6 +62,7 @@ CLIENT_SOURCES = \
storage_conf.h storage_conf.c \
storage_driver.h storage_driver.c \
storage_backend.h storage_backend.c \
+ storage_backend_fs.h storage_backend_fs.c \
util.c util.h
SERVER_SOURCES = \
diff -r 686cf593fe28 src/storage_backend.c
--- a/src/storage_backend.c Tue Feb 19 17:04:59 2008 -0500
+++ b/src/storage_backend.c Tue Feb 19 17:22:04 2008 -0500
@@ -40,10 +40,24 @@
#include "util.h"
#include "storage_backend.h"
+#include "storage_backend_fs.h"
+
+static virStorageBackendPtr backends[] = {
+ &virStorageBackendDirectory,
+#if WITH_STORAGE_FS
+ &virStorageBackendFileSystem,
+ &virStorageBackendNetFileSystem,
+#endif
+};
virStorageBackendPtr
virStorageBackendForType(int type) {
+ unsigned 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;
@@ -68,6 +82,15 @@ virStorageBackendVolOptionsForType(int t
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
+
virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
_("unknown storage backend type %s"), type);
return -1;
@@ -75,6 +98,17 @@ virStorageBackendFromString(const char *
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
+ }
+
virStorageReportError(NULL, VIR_ERR_INTERNAL_ERROR,
_("unknown storage backend type %d"), type);
return NULL;
diff -r 686cf593fe28 src/storage_backend_fs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_fs.c Tue Feb 19 17:22:05 2008 -0500
@@ -0,0 +1,1123 @@
+/*
+ * storage_backend_fs.c: storage backend for FS and directory handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#include <config.h>
+
+#include <sys/statvfs.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <mntent.h>
+#include <string.h>
+
+#include "storage_backend_fs.h"
+#include "storage_conf.h"
+#include "util.h"
+#include "config.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,
+};
+
+enum {
+ VIR_STORAGE_POOL_NETFS_AUTO = 0,
+ VIR_STORAGE_POOL_NETFS_NFS,
+};
+
+
+
+enum {
+ VIR_STORAGE_VOL_RAW,
+ 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,
+};
+
+/* Either 'magic' or 'extension' *must* be provided */
+struct {
+ int type; /* One of the constants above */
+ const char *magic; /* Optional string of file magic
+ * to check at head of file */
+ const char *extension; /* Optional file extension to check */
+ int endian; /* Endianness of file format */
+ int versionOffset; /* Byte offset from start of file
+ * where we find version number,
+ * -1 to skip version test */
+ int versionNumber; /* Version number to validate */
+ int sizeOffset; /* Byte offset from start of file
+ * where we find capacity info,
+ * -1 to use st_size as capacity */
+ int sizeBytes; /* Number of bytes for size field */
+ int sizeMultiplier; /* A scaling factor if size is not in bytes */
+} fileTypeInfo[] = {
+ /* Bochs */
+ /* XXX Untested
+ { VIR_STORAGE_VOL_BOCHS, "Bochs Virtual HD Image", NULL,
+ __LITTLE_ENDIAN, 64, 0x20000,
+ 32+16+16+4+4+4+4+4, 8, 1 },*/
+ /* CLoop */
+ /* XXX Untested
+ { VIR_STORAGE_VOL_CLOOP, "#!/bin/sh\n#V2.0 Format\nmodprobe cloop file=$0
&& mount -r -t iso9660 /dev/cloop $1\n", NULL,
+ __LITTLE_ENDIAN, -1, 0,
+ -1, 0, 0 }, */
+ /* Cow */
+ { VIR_STORAGE_VOL_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",
+ 0, -1, 0,
+ -1, 0, 0 },
+ /* XXX there's probably some magic for iso we can validate too... */
+ { VIR_STORAGE_VOL_ISO, NULL, ".iso",
+ 0, -1, 0,
+ -1, 0, 0 },
+ /* Parallels */
+ /* XXX Untested
+ { VIR_STORAGE_VOL_PARALLELS, "WithoutFreeSpace", NULL,
+ __LITTLE_ENDIAN, 16, 2,
+ 16+4+4+4+4, 4, 512 },
+ */
+ /* QCow */
+ { VIR_STORAGE_VOL_QCOW, "QFI", NULL,
+ __BIG_ENDIAN, 4, 1,
+ 4+4+8+4+4, 8, 1 },
+ /* QCow 2 */
+ { VIR_STORAGE_VOL_QCOW2, "QFI", NULL,
+ __BIG_ENDIAN, 4, 2,
+ 4+4+8+4+4, 8, 1 },
+ /* VMDK 3 */
+ /* XXX Untested
+ { VIR_STORAGE_VOL_VMDK, "COWD", NULL,
+ __LITTLE_ENDIAN, 4, 1,
+ 4+4+4, 4, 512 },
+ */
+ /* VMDK 4 */
+ { VIR_STORAGE_VOL_VMDK, "KDMV", NULL,
+ __LITTLE_ENDIAN, 4, 1,
+ 4+4+4, 8, 512 },
+ /* Connectix / VirtualPC */
+ /* XXX Untested
+ { VIR_STORAGE_VOL_VPC, "conectix", NULL,
+ __BIG_ENDIAN, -1, 0,
+ -1, 0, 0},
+ */
+};
+
+
+
+
+static int
+virStorageBackendFileSystemVolFormatFromString(virConnectPtr conn,
+ const char *format) {
+ if (format == NULL)
+ return VIR_STORAGE_VOL_RAW;
+
+ if (STREQ(format, "raw"))
+ return VIR_STORAGE_VOL_RAW;
+ if (STREQ(format, "dir"))
+ return VIR_STORAGE_VOL_DIR;
+ if (STREQ(format, "bochs"))
+ return VIR_STORAGE_VOL_BOCHS;
+ if (STREQ(format, "cow"))
+ return VIR_STORAGE_VOL_COW;
+ if (STREQ(format, "cloop"))
+ return VIR_STORAGE_VOL_CLOOP;
+ if (STREQ(format, "dmg"))
+ return VIR_STORAGE_VOL_DMG;
+ if (STREQ(format, "iso"))
+ return VIR_STORAGE_VOL_ISO;
+ if (STREQ(format, "qcow"))
+ return VIR_STORAGE_VOL_QCOW;
+ if (STREQ(format, "qcow2"))
+ return VIR_STORAGE_VOL_QCOW2;
+ if (STREQ(format, "vmdk"))
+ return VIR_STORAGE_VOL_VMDK;
+ if (STREQ(format, "vpc"))
+ return VIR_STORAGE_VOL_VPC;
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %s"), format);
+ return -1;
+}
+
+static const char *
+virStorageBackendFileSystemVolFormatToString(virConnectPtr conn,
+ int format) {
+ switch (format) {
+ case VIR_STORAGE_VOL_RAW:
+ return "raw";
+ case VIR_STORAGE_VOL_DIR:
+ return "dir";
+ case VIR_STORAGE_VOL_BOCHS:
+ return "bochs";
+ case VIR_STORAGE_VOL_CLOOP:
+ return "cloop";
+ case VIR_STORAGE_VOL_COW:
+ return "cow";
+ case VIR_STORAGE_VOL_DMG:
+ return "dmg";
+ case VIR_STORAGE_VOL_ISO:
+ return "iso";
+ case VIR_STORAGE_VOL_QCOW:
+ return "qcow";
+ case VIR_STORAGE_VOL_QCOW2:
+ return "qcow2";
+ case VIR_STORAGE_VOL_VMDK:
+ return "vmdk";
+ case VIR_STORAGE_VOL_VPC:
+ return "vpc";
+ }
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %d"), format);
+ return NULL;
+}
+
+
+static int
+virStorageBackendFileSystemPoolFormatFromString(virConnectPtr conn,
+ const char *format) {
+ if (format == NULL)
+ return VIR_STORAGE_POOL_FS_AUTO;
+
+ if (STREQ(format, "auto"))
+ return VIR_STORAGE_POOL_FS_AUTO;
+ if (STREQ(format, "ext2"))
+ return VIR_STORAGE_POOL_FS_EXT2;
+ if (STREQ(format, "ext3"))
+ return VIR_STORAGE_POOL_FS_EXT3;
+ if (STREQ(format, "ext4"))
+ return VIR_STORAGE_POOL_FS_EXT4;
+ if (STREQ(format, "ufs"))
+ return VIR_STORAGE_POOL_FS_UFS;
+ if (STREQ(format, "iso9660"))
+ return VIR_STORAGE_POOL_FS_ISO;
+ if (STREQ(format, "udf"))
+ return VIR_STORAGE_POOL_FS_UDF;
+ if (STREQ(format, "gfs"))
+ return VIR_STORAGE_POOL_FS_GFS;
+ if (STREQ(format, "gfs2"))
+ return VIR_STORAGE_POOL_FS_GFS2;
+ if (STREQ(format, "vfat"))
+ return VIR_STORAGE_POOL_FS_VFAT;
+ if (STREQ(format, "hfs+"))
+ return VIR_STORAGE_POOL_FS_HFSPLUS;
+ if (STREQ(format, "xfs"))
+ return VIR_STORAGE_POOL_FS_XFS;
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %s"), format);
+ return -1;
+}
+
+static const char *
+virStorageBackendFileSystemPoolFormatToString(virConnectPtr conn,
+ int format) {
+ switch (format) {
+ case VIR_STORAGE_POOL_FS_AUTO:
+ return "auto";
+ case VIR_STORAGE_POOL_FS_EXT2:
+ return "ext2";
+ case VIR_STORAGE_POOL_FS_EXT3:
+ return "ext3";
+ case VIR_STORAGE_POOL_FS_EXT4:
+ return "ext4";
+ case VIR_STORAGE_POOL_FS_UFS:
+ return "ufs";
+ case VIR_STORAGE_POOL_FS_ISO:
+ return "iso";
+ case VIR_STORAGE_POOL_FS_UDF:
+ return "udf";
+ case VIR_STORAGE_POOL_FS_GFS:
+ return "gfs";
+ case VIR_STORAGE_POOL_FS_GFS2:
+ return "gfs2";
+ case VIR_STORAGE_POOL_FS_VFAT:
+ return "vfat";
+ case VIR_STORAGE_POOL_FS_HFSPLUS:
+ return "hfs+";
+ case VIR_STORAGE_POOL_FS_XFS:
+ return "xfs";
+ }
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %d"), format);
+ return NULL;
+}
+
+
+static int
+virStorageBackendFileSystemNetPoolFormatFromString(virConnectPtr conn,
+ const char *format) {
+ if (format == NULL)
+ return VIR_STORAGE_POOL_NETFS_AUTO;
+
+ if (STREQ(format, "auto"))
+ return VIR_STORAGE_POOL_NETFS_AUTO;
+ if (STREQ(format, "nfs"))
+ return VIR_STORAGE_POOL_NETFS_NFS;
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %s"), format);
+ return -1;
+}
+
+static const char *
+virStorageBackendFileSystemNetPoolFormatToString(virConnectPtr conn,
+ int format) {
+ switch (format) {
+ case VIR_STORAGE_POOL_NETFS_AUTO:
+ return "auto";
+ case VIR_STORAGE_POOL_NETFS_NFS:
+ return "nfs";
+ }
+
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported volume format %d"), format);
+ return NULL;
+}
+
+
+/**
+ * Probe the header of a file to determine what type of disk image
+ * it is, and info about its capacity if available.
+ */
+static int virStorageBackendProbeFile(virConnectPtr conn,
+ virStorageVolDefPtr def) {
+ int fd;
+ char head[4096];
+ int len, i, ret;
+
+ if ((fd = open(def->target.path, O_RDONLY)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot open volume '%s': %s"),
+ def->target.path, strerror(errno));
+ return -1;
+ }
+
+ if ((ret = virStorageBackendUpdateVolInfoFD(conn, def, fd, 1)) < 0) {
+ close(fd);
+ return ret; /* Take care to propagate ret, it is not always -1 */
+ }
+
+ if ((len = read(fd, head, sizeof(head))) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read header '%s': %s"),
+ def->target.path, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ /* First check file magic */
+ for (i = 0 ; i < sizeof(fileTypeInfo)/sizeof(fileTypeInfo[0]) ; i++) {
+ int mlen;
+ if (fileTypeInfo[i].magic == NULL)
+ continue;
+
+ /* Validate magic data */
+ mlen = strlen(fileTypeInfo[i].magic);
+ if (mlen > len)
+ continue;
+ if (memcmp(head, fileTypeInfo[i].magic, mlen) != 0)
+ continue;
+
+ /* Validate version number info */
+ if (fileTypeInfo[i].versionNumber != -1) {
+ int version;
+
+ if (fileTypeInfo[i].endian == __LITTLE_ENDIAN) {
+ version = (head[fileTypeInfo[i].versionOffset+3] << 24) |
+ (head[fileTypeInfo[i].versionOffset+2] << 16) |
+ (head[fileTypeInfo[i].versionOffset+1] << 8) |
+ head[fileTypeInfo[i].versionOffset];
+ } else {
+ version = (head[fileTypeInfo[i].versionOffset] << 24) |
+ (head[fileTypeInfo[i].versionOffset+1] << 16) |
+ (head[fileTypeInfo[i].versionOffset+2] << 8) |
+ head[fileTypeInfo[i].versionOffset+3];
+ }
+ if (version != fileTypeInfo[i].versionNumber)
+ continue;
+ }
+
+ /* Optionally extract capacity from file */
+ if (fileTypeInfo[i].sizeOffset != -1) {
+ if (fileTypeInfo[i].endian == __LITTLE_ENDIAN) {
+ def->capacity =
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7] << 56)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 48)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 40)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 32)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 24)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 16)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 8)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset]);
+ } else {
+ def->capacity =
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset] << 56) |
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+1] << 48)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+2] << 40)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+3] << 32)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+4] << 24)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+5] << 16)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+6] << 8)
|
+ ((unsigned long long)head[fileTypeInfo[i].sizeOffset+7]);
+ }
+ /* Avoid unlikely, but theoretically possible overflow */
+ if (def->capacity > (ULLONG_MAX / fileTypeInfo[i].sizeMultiplier))
+ continue;
+ def->capacity *= fileTypeInfo[i].sizeMultiplier;
+ }
+
+ /* Validation passed, we know the file format now */
+ def->target.format = fileTypeInfo[i].type;
+ return 0;
+ }
+
+ /* No magic, so check file extension */
+ for (i = 0 ; i < sizeof(fileTypeInfo)/sizeof(fileTypeInfo[0]) ; i++) {
+ if (fileTypeInfo[i].extension == NULL)
+ continue;
+
+ if (!virFileHasSuffix(def->target.path, fileTypeInfo[i].extension))
+ continue;
+
+ def->target.format = fileTypeInfo[i].type;
+ return 0;
+ }
+
+ /* All fails, so call it a raw file */
+ def->target.format = VIR_STORAGE_VOL_RAW;
+ return 0;
+}
+
+#if WITH_STORAGE_FS
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to check for status
+ *
+ * Determine if a storage pool is already mounted
+ *
+ * Return 0 if not mounted, 1 if mounted, -1 on error
+ */
+static int
+virStorageBackendFileSystemIsMounted(virConnectPtr conn,
+ virStoragePoolObjPtr pool) {
+ FILE *mtab;
+ struct mntent *ent;
+
+ if ((mtab = fopen(_PATH_MOUNTED, "r")) == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read %s: %s"),
+ _PATH_MOUNTED, strerror(errno));
+ return -1;
+ }
+
+ while ((ent = getmntent(mtab)) != NULL) {
+ if (STREQ(ent->mnt_dir, pool->def->target.path)) {
+ fclose(mtab);
+ return 1;
+ }
+ }
+
+ fclose(mtab);
+ return 0;
+}
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to mount
+ *
+ * Ensure that a FS storage pool is mounted on its target location.
+ * If already mounted, this is a no-op
+ *
+ * Returns 0 if successfully mounted, -1 on error
+ */
+static int
+virStorageBackendFileSystemMount(virConnectPtr conn,
+ virStoragePoolObjPtr pool) {
+ char *src;
+ const char *mntargv[] = {
+ MOUNT,
+ "-t",
+ pool->def->type == VIR_STORAGE_POOL_FS ?
+ virStorageBackendFileSystemPoolFormatToString(conn,
+ pool->def->source.format) :
+ virStorageBackendFileSystemNetPoolFormatToString(conn,
+
pool->def->source.format),
+ NULL, /* Fill in shortly - careful not to add extra fields before this */
+ pool->def->target.path,
+ NULL,
+ };
+ int ret;
+
+ if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
+ if (pool->def->source.host.name == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing source host"));
+ return -1;
+ }
+ if (pool->def->source.dir == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing source path"));
+ return -1;
+ }
+ } else {
+ if (pool->def->source.ndevice != 1) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing source device"));
+ return -1;
+ }
+ }
+
+ /* Short-circuit is already mounted */
+ if ((ret = virStorageBackendFileSystemIsMounted(conn, pool)) != 0) {
+ if (ret < 0)
+ return -1;
+ else
+ return 0;
+ }
+
+ if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
+ src = malloc(strlen(pool->def->source.host.name) +
+ 1 + strlen(pool->def->source.dir) + 1);
+ strcpy(src, pool->def->source.host.name);
+ strcat(src, ":");
+ strcat(src, pool->def->source.dir);
+ } else {
+ src = strdup(pool->def->source.devices[0].path);
+ }
+ if (src == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("source"));
+ return -1;
+ }
+ mntargv[3] = src;
+
+ if (virRun(conn, (char**)mntargv, NULL) < 0) {
+ free(src);
+ return -1;
+ }
+ free(src);
+ return 0;
+}
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to unmount
+ *
+ * Ensure that a FS storage pool is not mounted on its target location.
+ * If already unmounted, this is a no-op
+ *
+ * Returns 0 if successfully unmounted, -1 on error
+ */
+static int
+virStorageBackendFileSystemUnmount(virConnectPtr conn,
+ virStoragePoolObjPtr pool) {
+ const char *mntargv[3];
+ int ret;
+
+ if (pool->def->type == VIR_STORAGE_POOL_NETFS) {
+ if (pool->def->source.host.name == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing source host"));
+ return -1;
+ }
+ if (pool->def->source.dir == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing source dir"));
+ return -1;
+ }
+ } else {
+ if (pool->def->source.ndevice != 1) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("missing source device"));
+ return -1;
+ }
+ }
+
+ /* Short-circuit if already unmounted */
+ if ((ret = virStorageBackendFileSystemIsMounted(conn, pool)) != 1) {
+ if (ret < 0)
+ return -1;
+ else
+ return 0;
+ }
+
+ mntargv[0] = UMOUNT;
+ mntargv[1] = pool->def->target.path;
+ mntargv[2] = NULL;
+
+ if (virRun(conn, (char**)mntargv, NULL) < 0) {
+ return -1;
+ }
+ return 0;
+}
+#endif /* WITH_STORAGE_FS */
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to start
+ *
+ * Starts a directory or FS based storage pool.
+ *
+ * - If it is a FS based pool, mounts the unlying source device on the pool
+ *
+ * Returns 0 on success, -1 on error
+ */
+#if WITH_STORAGE_FS
+static int
+virStorageBackendFileSystemStart(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ if (pool->def->type != VIR_STORAGE_POOL_DIR &&
+ virStorageBackendFileSystemMount(conn, pool) < 0)
+ return -1;
+
+ return 0;
+}
+#endif /* WITH_STORAGE_FS */
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to build
+ *
+ * Build a directory or FS based storage pool.
+ *
+ * - If it is a FS based pool, mounts the unlying source device on the pool
+ *
+ * Returns 0 on success, -1 on error
+ */
+static int
+virStorageBackendFileSystemBuild(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ if (virFileMakePath(pool->def->target.path) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create path '%s': %s"),
+ pool->def->target.path, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Iterate over the pool's directory and enumerate all disk images
+ * within it. This is non-recursive.
+ */
+static int
+virStorageBackendFileSystemRefresh(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ DIR *dir;
+ struct dirent *ent;
+ struct statvfs sb;
+
+ if (!(dir = opendir(pool->def->target.path))) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot open path '%s': %s"),
+ pool->def->target.path, strerror(errno));
+ goto cleanup;
+ }
+
+ while ((ent = readdir(dir)) != NULL) {
+ virStorageVolDefPtr vol;
+ int ret;
+
+ vol = calloc(1, sizeof(virStorageVolDef));
+ if (vol == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("volume"));
+ goto cleanup;
+ }
+
+ vol->name = strdup(ent->d_name);
+ if (vol->name == NULL) {
+ free(vol);
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("volume name"));
+ goto cleanup;
+ }
+
+ vol->target.format = VIR_STORAGE_VOL_RAW; /* Real value is filled in during
probe */
+ vol->target.path = malloc(strlen(pool->def->target.path) +
+ 1 + strlen(vol->name) + 1);
+ if (vol->target.path == NULL) {
+ free(vol->target.path);
+ free(vol);
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("volume name"));
+ goto cleanup;
+ }
+ strcpy(vol->target.path, pool->def->target.path);
+ strcat(vol->target.path, "/");
+ strcat(vol->target.path, vol->name);
+ if ((vol->key = strdup(vol->target.path)) == NULL) {
+ free(vol->name);
+ free(vol->target.path);
+ free(vol);
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY,
+ _("volume key"));
+ goto cleanup;
+ }
+
+ if ((ret = virStorageBackendProbeFile(conn, vol) < 0)) {
+ free(vol->key);
+ free(vol->name);
+ free(vol->target.path);
+ free(vol);
+ if (ret == -1)
+ goto cleanup;
+ else
+ /* Silently ignore non-regular files,
+ * eg '.' '..', 'lost+found' */
+ continue;
+ }
+
+ vol->next = pool->volumes;
+ pool->volumes = vol;
+ pool->nvolumes++;
+ continue;
+ }
+ closedir(dir);
+
+
+ if (statvfs(pool->def->target.path, &sb) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot statvfs path '%s': %s"),
+ pool->def->target.path, strerror(errno));
+ return -1;
+ }
+ pool->def->capacity = ((unsigned long long)sb.f_frsize *
+ (unsigned long long)sb.f_blocks);
+ pool->def->available = ((unsigned long long)sb.f_bfree *
+ (unsigned long long)sb.f_bsize);
+ pool->def->allocation = pool->def->capacity -
pool->def->available;
+
+ return 0;
+
+ cleanup:
+ closedir(dir);
+ virStoragePoolObjClearVols(pool);
+ return -1;
+}
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to start
+ *
+ * Stops a directory or FS based storage pool.
+ *
+ * - If it is a FS based pool, unmounts the unlying source device on the pool
+ * - Releases all cached data about volumes
+ */
+#if WITH_STORAGE_FS
+static int
+virStorageBackendFileSystemStop(virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ if (pool->def->type != VIR_STORAGE_POOL_DIR &&
+ virStorageBackendFileSystemUnmount(conn, pool) < 0)
+ return -1;
+
+ return 0;
+}
+#endif /* WITH_STORAGE_FS */
+
+
+/**
+ * @conn connection to report errors against
+ * @pool storage pool to build
+ *
+ * Build a directory or FS based storage pool.
+ *
+ * - If it is a FS based pool, mounts the unlying source device on the pool
+ *
+ * Returns 0 on success, -1 on error
+ */
+static int
+virStorageBackendFileSystemDelete(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ /* XXX delete all vols first ? */
+
+ if (unlink(pool->def->target.path) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot unlink path '%s': %s"),
+ pool->def->target.path, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Allocate a new file as a volume. This is either done directly
+ * for raw/sparse files, or by calling qemu-img/qcow-create for
+ * special kinds of files
+ */
+static int
+virStorageBackendFileSystemVolCreate(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+ int fd;
+
+ vol->target.path = malloc(strlen(pool->def->target.path) +
+ 1 + strlen(vol->name) + 1);
+ if (vol->target.path == NULL) {
+ virStorageReportError(conn, VIR_ERR_NO_MEMORY, _("target"));
+ return -1;
+ }
+ strcpy(vol->target.path, pool->def->target.path);
+ strcat(vol->target.path, "/");
+ strcat(vol->target.path, vol->name);
+ vol->key = strdup(vol->target.path);
+ if (vol->key == NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("storage vol key"));
+ return -1;
+ }
+
+ if (vol->target.format == VIR_STORAGE_VOL_RAW) {
+ if ((fd = open(vol->target.path, O_RDWR | O_CREAT | O_EXCL,
+ vol->target.perms.mode)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create path '%s': %s"),
+ vol->target.path, strerror(errno));
+ return -1;
+ }
+
+ /* Pre-allocate any data if requested */
+ /* XXX slooooooooooooooooow.
+ * Need to add in progress bars & bg thread somehow */
+ if (vol->allocation) {
+ unsigned long long remain = vol->allocation;
+ static const char const zeros[4096];
+ while (remain) {
+ int bytes = sizeof(zeros);
+ if (bytes > remain)
+ bytes = remain;
+ if ((bytes = write(fd, zeros, bytes)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot fill file '%s':
%s"),
+ vol->target.path, strerror(errno));
+ unlink(vol->target.path);
+ close(fd);
+ return -1;
+ }
+ remain -= bytes;
+ }
+ }
+
+ /* Now seek to final size, possibly making the file sparse */
+ if (ftruncate(fd, vol->capacity) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot extend file '%s': %s"),
+ vol->target.path, strerror(errno));
+ unlink(vol->target.path);
+ close(fd);
+ return -1;
+ }
+ } else if (vol->target.format == VIR_STORAGE_VOL_DIR) {
+ if (mkdir(vol->target.path, vol->target.perms.mode) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot create path '%s': %s"),
+ vol->target.path, strerror(errno));
+ return -1;
+ }
+
+ if ((fd = open(vol->target.path, O_RDWR)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read path '%s': %s"),
+ vol->target.path, strerror(errno));
+ return -1;
+ }
+ } else {
+#if HAVE_QEMU_IMG
+ const char *type;
+ char size[100];
+ const char *imgargv[7];
+
+ if ((type = virStorageBackendFileSystemVolFormatToString(conn,
+ vol->target.format))
== NULL) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unknown storage vol type %d"),
+ vol->target.format);
+ return -1;
+ }
+
+ /* Size in KB */
+ snprintf(size, sizeof(size), "%llu", vol->capacity/1024);
+
+ imgargv[0] = QEMU_IMG;
+ imgargv[1] = "create";
+ imgargv[2] = "-f";
+ imgargv[3] = type;
+ imgargv[4] = vol->target.path;
+ imgargv[5] = size;
+ imgargv[6] = NULL;
+
+ if (virRun(conn, (char **)imgargv, NULL) < 0) {
+ unlink(vol->target.path);
+ return -1;
+ }
+
+ if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read path '%s': %s"),
+ vol->target.path, strerror(errno));
+ unlink(vol->target.path);
+ return -1;
+ }
+#elif HAVE_QCOW_CREATE
+ /*
+ * Xen removed the fully-functional qemu-img, and replaced it
+ * with a partially functional qcow-create. Go figure ??!?
+ */
+ char size[100];
+ const char *imgargv[4];
+
+ if (vol->target.format != VIR_STORAGE_VOL_QCOW2) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("unsupported storage vol type %d"),
+ vol->target.format);
+ return -1;
+ }
+
+ /* Size in MB - yes different units to qemu-img :-( */
+ snprintf(size, sizeof(size), "%llu", vol->capacity/1024/1024);
+
+ imgargv[0] = QCOW_CREATE;
+ imgargv[1] = size;
+ imgargv[2] = vol->target.path;
+ imgargv[3] = NULL;
+
+ if (virRun(conn, (char **)imgargv, NULL) < 0) {
+ unlink(vol->target.path);
+ return -1;
+ }
+
+ if ((fd = open(vol->target.path, O_RDONLY)) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot read path '%s': %s"),
+ vol->target.path, strerror(errno));
+ unlink(vol->target.path);
+ return -1;
+ }
+#else
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("creation of non-raw images is not supported without
qemu-img"));
+ return -1;
+#endif
+ }
+
+ /* We can only chown/grp if root */
+ if (getuid() == 0) {
+ if (fchown(fd, vol->target.perms.uid, vol->target.perms.gid) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot set file owner '%s': %s"),
+ vol->target.path, strerror(errno));
+ unlink(vol->target.path);
+ close(fd);
+ return -1;
+ }
+ }
+ if (fchmod(fd, vol->target.perms.mode) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot set file mode '%s': %s"),
+ vol->target.path, strerror(errno));
+ unlink(vol->target.path);
+ close(fd);
+ return -1;
+ }
+
+ /* Refresh allocation / permissions info, but not capacity */
+ if (virStorageBackendUpdateVolInfoFD(conn, vol, fd, 0) < 0) {
+ unlink(vol->target.path);
+ close(fd);
+ return -1;
+ }
+
+ if (close(fd) < 0) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot close file '%s': %s"),
+ vol->target.path, strerror(errno));
+ unlink(vol->target.path);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Remove a volume - just unlinks for now
+ */
+static int
+virStorageBackendFileSystemVolDelete(virConnectPtr conn,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ if (unlink(vol->target.path) < 0) {
+ /* Silently ignore failures where the vol has already gone away */
+ if (errno != ENOENT) {
+ virStorageReportError(conn, VIR_ERR_INTERNAL_ERROR,
+ _("cannot unlink file '%s': %s"),
+ vol->target.path, strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * Update info about a volume's capacity/allocation
+ */
+static int
+virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol)
+{
+ /* Refresh allocation / permissions info in case its changed */
+ return virStorageBackendUpdateVolInfo(conn, vol, 0);
+}
+
+virStorageBackend virStorageBackendDirectory = {
+ .type = VIR_STORAGE_POOL_DIR,
+
+ .buildPool = virStorageBackendFileSystemBuild,
+ .refreshPool = virStorageBackendFileSystemRefresh,
+ .deletePool = virStorageBackendFileSystemDelete,
+ .createVol = virStorageBackendFileSystemVolCreate,
+ .refreshVol = virStorageBackendFileSystemVolRefresh,
+ .deleteVol = virStorageBackendFileSystemVolDelete,
+
+ .volOptions = {
+ .formatFromString = virStorageBackendFileSystemVolFormatFromString,
+ .formatToString = virStorageBackendFileSystemVolFormatToString,
+ },
+ .volType = VIR_STORAGE_VOL_FILE,
+};
+
+#if WITH_STORAGE_FS
+virStorageBackend virStorageBackendFileSystem = {
+ .type = VIR_STORAGE_POOL_FS,
+
+ .buildPool = virStorageBackendFileSystemBuild,
+ .startPool = virStorageBackendFileSystemStart,
+ .refreshPool = virStorageBackendFileSystemRefresh,
+ .stopPool = virStorageBackendFileSystemStop,
+ .deletePool = virStorageBackendFileSystemDelete,
+ .createVol = virStorageBackendFileSystemVolCreate,
+ .refreshVol = virStorageBackendFileSystemVolRefresh,
+ .deleteVol = virStorageBackendFileSystemVolDelete,
+
+ .poolOptions = {
+ .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_DEVICE),
+ .formatFromString = virStorageBackendFileSystemPoolFormatFromString,
+ .formatToString = virStorageBackendFileSystemPoolFormatToString,
+ },
+ .volOptions = {
+ .formatFromString = virStorageBackendFileSystemVolFormatFromString,
+ .formatToString = virStorageBackendFileSystemVolFormatToString,
+ },
+ .volType = VIR_STORAGE_VOL_FILE,
+};
+virStorageBackend virStorageBackendNetFileSystem = {
+ .type = VIR_STORAGE_POOL_NETFS,
+
+ .buildPool = virStorageBackendFileSystemBuild,
+ .startPool = virStorageBackendFileSystemStart,
+ .refreshPool = virStorageBackendFileSystemRefresh,
+ .stopPool = virStorageBackendFileSystemStop,
+ .deletePool = virStorageBackendFileSystemDelete,
+ .createVol = virStorageBackendFileSystemVolCreate,
+ .refreshVol = virStorageBackendFileSystemVolRefresh,
+ .deleteVol = virStorageBackendFileSystemVolDelete,
+
+ .poolOptions = {
+ .flags = (VIR_STORAGE_BACKEND_POOL_SOURCE_HOST |
+ VIR_STORAGE_BACKEND_POOL_SOURCE_DIR),
+ .formatFromString = virStorageBackendFileSystemNetPoolFormatFromString,
+ .formatToString = virStorageBackendFileSystemNetPoolFormatToString,
+ },
+ .volOptions = {
+ .formatFromString = virStorageBackendFileSystemVolFormatFromString,
+ .formatToString = virStorageBackendFileSystemVolFormatToString,
+ },
+ .volType = VIR_STORAGE_VOL_FILE,
+};
+#endif /* WITH_STORAGE_FS */
+
+/*
+ * 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 686cf593fe28 src/storage_backend_fs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/storage_backend_fs.h Tue Feb 19 17:22:05 2008 -0500
@@ -0,0 +1,49 @@
+/*
+ * storage_backend_fs.h: storage backend for FS and directory handling
+ *
+ * Copyright (C) 2007-2008 Red Hat, Inc.
+ * Copyright (C) 2007-2008 Daniel P. Berrange
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Daniel P. Berrange <berrange(a)redhat.com>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_FS_H__
+#define __VIR_STORAGE_BACKEND_FS_H__
+
+#include "storage_backend.h"
+
+#if WITH_STORAGE_FS
+extern virStorageBackend virStorageBackendFileSystem;
+extern virStorageBackend virStorageBackendNetFileSystem;
+#endif
+extern virStorageBackend virStorageBackendDirectory;
+
+#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:
+ */
--
|=- 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 -=|