[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libvir] [for discussion only] virDomainBlockPeek preliminary implementation



The attached patch (for discussion only) adds a virDomainBlockPeek call, allowing callers to peek into the block devices of domains.

+/**
+ * virDomainBlockPeek:
+ * @dom: pointer to the domain object
+ * @path: path to the block device
+ * @offset: offset within block device
+ * @size: size to read
+ * @buffer: return buffer (must be at least size bytes)
+ *
+ * This function allows you to read the contents of a domain's
+ * disk device.
+ *
+ * Typical uses for this are to determine if the domain has
+ * written a Master Boot Record (indicating that the domain
+ * has completed installation), or to try to work out the state
+ * of the domain's filesystems.
+ *
+ * (Note that in the local case you might try to open the
+ * block device or file directly, but that won't work in the
+ * remote case, nor if you don't have sufficient permission.
+ * Hence the need for this call).
+ *
+ * 'path' must be a device or file corresponding to the domain.
+ * In other words it must be the precise string returned in
+ * a <disk><source dev='...'/></disk> from
+ * virDomainGetXMLDesc.
+ *
+ * 'offset' and 'size' represent an area which must lie entirely
+ * within the device or file.  'size' may be 0 to test if the
+ * call would succeed.
+ *
+ * 'buffer' is the return buffer and must be at least 'size' bytes.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainBlockPeek (virDomainPtr dom,
+                    const char *path,
+                    long long offset /* really 64 bits */,
+                    size_t size,
+                    void *buffer)

The patch doesn't include:
 - remote
 - qemu
 - Xen < 3.0.3 inactive domains

I will add these if I get favourable feedback.

Rich.

--
Emerging Technologies, Red Hat - http://et.redhat.com/~rjones/
Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod
Street, Windsor, Berkshire, SL4 1TE, United Kingdom.  Registered in
England and Wales under Company Registration No. 03798903
Index: include/libvirt/libvirt.h
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h,v
retrieving revision 1.60
diff -u -p -r1.60 libvirt.h
--- include/libvirt/libvirt.h	15 Oct 2007 21:38:56 -0000	1.60
+++ include/libvirt/libvirt.h	16 Oct 2007 14:38:37 -0000
@@ -448,7 +448,11 @@ int                     virDomainInterfa
 						 const char *path,
 						 virDomainInterfaceStatsPtr stats,
 						 size_t size);
-
+int                     virDomainBlockPeek (virDomainPtr dom,
+					    const char *path,
+					    long long offset,
+					    size_t size,
+					    void *buffer);
 
 /*
  * defined but not running domains
Index: include/libvirt/libvirt.h.in
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v
retrieving revision 1.38
diff -u -p -r1.38 libvirt.h.in
--- include/libvirt/libvirt.h.in	15 Oct 2007 21:38:56 -0000	1.38
+++ include/libvirt/libvirt.h.in	16 Oct 2007 14:38:38 -0000
@@ -448,7 +448,11 @@ int                     virDomainInterfa
 						 const char *path,
 						 virDomainInterfaceStatsPtr stats,
 						 size_t size);
-
+int                     virDomainBlockPeek (virDomainPtr dom,
+					    const char *path,
+					    long long offset,
+					    size_t size,
+					    void *buffer);
 
 /*
  * defined but not running domains
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.38
diff -u -p -r1.38 driver.h
--- src/driver.h	15 Oct 2007 21:38:56 -0000	1.38
+++ src/driver.h	16 Oct 2007 14:38:38 -0000
@@ -223,6 +223,13 @@ typedef int
                      struct _virDomainInterfaceStats *stats);
 
 typedef int
+    (*virDrvDomainBlockPeek)
+                    (virDomainPtr domain,
+                     const char *path,
+                     long long offset, size_t size,
+                     void *buffer);
+
+typedef int
     (*virDrvDomainMigratePrepare)
                     (virConnectPtr dconn,
                      char **cookie,
@@ -333,6 +340,7 @@ struct _virDriver {
     virDrvDomainMigrateFinish	domainMigrateFinish;
     virDrvDomainBlockStats      domainBlockStats;
     virDrvDomainInterfaceStats  domainInterfaceStats;
+    virDrvDomainBlockPeek		domainBlockPeek;
 	virDrvNodeGetCellsFreeMemory	nodeGetCellsFreeMemory;
 	virDrvNodeGetFreeMemory		getFreeMemory;
 };
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.103
diff -u -p -r1.103 libvirt.c
--- src/libvirt.c	15 Oct 2007 21:38:56 -0000	1.103
+++ src/libvirt.c	16 Oct 2007 14:38:40 -0000
@@ -2176,7 +2176,78 @@ virDomainInterfaceStats (virDomainPtr do
     return -1;
 }
 
+/**
+ * virDomainBlockPeek:
+ * @dom: pointer to the domain object
+ * @path: path to the block device
+ * @offset: offset within block device
+ * @size: size to read
+ * @buffer: return buffer (must be at least size bytes)
+ *
+ * This function allows you to read the contents of a domain's
+ * disk device.
+ *
+ * Typical uses for this are to determine if the domain has
+ * written a Master Boot Record (indicating that the domain
+ * has completed installation), or to try to work out the state
+ * of the domain's filesystems.
+ *
+ * (Note that in the local case you might try to open the
+ * block device or file directly, but that won't work in the
+ * remote case, nor if you don't have sufficient permission.
+ * Hence the need for this call).
+ *
+ * 'path' must be a device or file corresponding to the domain.
+ * In other words it must be the precise string returned in
+ * a <disk><source dev='...'/></disk> from
+ * virDomainGetXMLDesc.
+ *
+ * 'offset' and 'size' represent an area which must lie entirely
+ * within the device or file.  'size' may be 0 to test if the
+ * call would succeed.
+ *
+ * 'buffer' is the return buffer and must be at least 'size' bytes.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainBlockPeek (virDomainPtr dom,
+                    const char *path,
+                    long long offset /* really 64 bits */,
+                    size_t size,
+                    void *buffer)
+{
+    virConnectPtr conn;
+    DEBUG("domain=%p, path=%s, offset=%lld, size=%zi, buffer=%p",
+          dom, path, offset, size, buffer);
+
+    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+        virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return -1;
+    }
+    conn = dom->conn;
+
+    if (!path) {
+        virLibDomainError (dom, VIR_ERR_INVALID_ARG, "path == NULL");
+        return -1;
+    }
+    /* Allow size == 0 as an access test. */
+    if (offset < 0) {
+        virLibDomainError (dom, VIR_ERR_INVALID_ARG,
+                           "offset is negative");
+        return -1;
+    }
+    if (size > 0 && !buffer) {
+        virLibDomainError (dom, VIR_ERR_INVALID_ARG, "buffer == NULL");
+        return -1;
+    }
 
+    if (conn->driver->domainBlockPeek)
+        return conn->driver->domainBlockPeek (dom, path, offset, size, buffer);
+
+    virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+}
 
 
 /************************************************************************
Index: src/libvirt_sym.version
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt_sym.version,v
retrieving revision 1.30
diff -u -p -r1.30 libvirt_sym.version
--- src/libvirt_sym.version	30 Sep 2007 13:22:16 -0000	1.30
+++ src/libvirt_sym.version	16 Oct 2007 14:38:40 -0000
@@ -70,6 +70,7 @@
 	virDomainSetSchedulerParameters;
 	virDomainBlockStats;
 	virDomainInterfaceStats;
+	virDomainBlockPeek;
 	virDomainAttachDevice;
 	virDomainDetachDevice;
 
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.30
diff -u -p -r1.30 qemu_driver.c
--- src/qemu_driver.c	12 Oct 2007 16:05:44 -0000	1.30
+++ src/qemu_driver.c	16 Oct 2007 14:38:42 -0000
@@ -2717,6 +2717,7 @@ static virDriver qemuDriver = {
     NULL, /* domainMigrateFinish */
     NULL, /* domainBlockStats */
     NULL, /* domainInterfaceStats */
+    NULL, /* domainBlockPeek */
     NULL, /* nodeGetCellsFreeMemory */
     NULL, /* getFreeMemory */
 };
Index: src/test.c
===================================================================
RCS file: /data/cvs/libvirt/src/test.c,v
retrieving revision 1.50
diff -u -p -r1.50 test.c
--- src/test.c	15 Oct 2007 14:32:35 -0000	1.50
+++ src/test.c	16 Oct 2007 14:38:43 -0000
@@ -1978,6 +1978,7 @@ static virDriver testDriver = {
     NULL, /* domainMigrateFinish */
     NULL, /* domainBlockStats */
     NULL, /* domainInterfaceStats */
+    NULL, /* domainBlockPeek */
     NULL, /* nodeGetCellsFreeMemory */
     NULL, /* getFreeMemory */
 };
Index: src/virsh.c
===================================================================
RCS file: /data/cvs/libvirt/src/virsh.c,v
retrieving revision 1.104
diff -u -p -r1.104 virsh.c
--- src/virsh.c	30 Sep 2007 13:22:16 -0000	1.104
+++ src/virsh.c	16 Oct 2007 14:38:46 -0000
@@ -230,6 +230,7 @@ static int vshCmddefHelp(vshControl * ct
 
 static vshCmdOpt *vshCommandOpt(vshCmd * cmd, const char *name);
 static int vshCommandOptInt(vshCmd * cmd, const char *name, int *found);
+static long long vshCommandOptInt64(vshCmd * cmd, const char *name, int *found);
 static char *vshCommandOptString(vshCmd * cmd, const char *name,
                                  int *found);
 static int vshCommandOptBool(vshCmd * cmd, const char *name);
@@ -783,6 +784,74 @@ cmdDomIfstat (vshControl *ctl, vshCmd *c
     return TRUE;
 }
 
+/* "domblkpeek" command
+ */
+static vshCmdInfo info_domblkpeek[] = {
+    {"syntax", "domblkpeek <domain> <path> <offset> <size>"},
+    {"help", gettext_noop("peek at a domain block device")},
+    {"desc", gettext_noop("Peek into a domain block device.")},
+    {NULL,NULL}
+};
+
+static vshCmdOptDef opts_domblkpeek[] = {
+    {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id or uuid")},
+    {"path", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("block device path")},
+    {"offset", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("start offset")},
+    {"size", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("size in bytes")},
+    {NULL, 0, 0, NULL}
+};
+
+static int
+cmdDomblkpeek (vshControl *ctl, vshCmd *cmd)
+{
+    virDomainPtr dom;
+    char *name, *path;
+    long long offset;
+    size_t size;
+    char *buffer;
+    int i, found;
+
+    if (!vshConnectionUsability (ctl, ctl->conn, TRUE))
+        return FALSE;
+
+    if (!(dom = vshCommandOptDomain (ctl, cmd, "domain", &name)))
+        return FALSE;
+
+    if (!(path = vshCommandOptString (cmd, "path", NULL)))
+        return FALSE;
+
+    offset = vshCommandOptInt64 (cmd, "offset", &found);
+    if (!found) return FALSE;
+
+    size = vshCommandOptInt (cmd, "size", &found);
+    if (!found) return FALSE;
+
+    buffer = malloc (size);
+    if (!buffer) {
+        vshError (ctl, FALSE, _("Memory allocation failed for buffer"));
+        virDomainFree(dom);
+        return FALSE;
+    }
+
+    if (virDomainBlockPeek (dom, path, offset, size, buffer) == -1) {
+        vshError (ctl, FALSE, _("Failed to peek block device %s %s"),
+                  name, path);
+        virDomainFree(dom);
+        return FALSE;
+    }
+
+    /* Dump out the memory - user can pipe into od/hexdump if they
+     * desire.
+     */
+    for (i = 0; i < size; ++i) {
+        putchar (buffer[i]);
+    }
+
+    free (buffer);
+    virDomainFree(dom);
+    return TRUE;
+}
+
 /*
  * "suspend" command
  */
@@ -3702,6 +3771,7 @@ static vshCmdDef commands[] = {
     {"domstate", cmdDomstate, opts_domstate, info_domstate},
     {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
     {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat},
+    {"domblkpeek", cmdDomblkpeek, opts_domblkpeek, info_domblkpeek},
     {"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
     {"freecell", cmdFreecell, opts_freecell, info_freecell},
     {"hostname", cmdHostname, NULL, info_hostname},
@@ -3953,6 +4023,28 @@ vshCommandOptInt(vshCmd * cmd, const cha
 }
 
 /*
+ * Returns option as 64 bit integer.
+ */
+static long long
+vshCommandOptInt64(vshCmd * cmd, const char *name, int *found)
+{
+    vshCmdOpt *arg = vshCommandOpt(cmd, name);
+    long long res = 0, num_found = FALSE;
+    char *end_p = NULL;
+
+    if ((arg != NULL) && (arg->data != NULL)) {
+        res = strtoll(arg->data, &end_p, 10);
+	if ((arg->data == end_p) || (*end_p!= 0))
+	    num_found = FALSE;
+	else
+	    num_found = TRUE;
+    }
+    if (found)
+        *found = num_found;
+    return res;
+}
+
+/*
  * Returns option as STRING
  */
 static char *
Index: src/xen_unified.c
===================================================================
RCS file: /data/cvs/libvirt/src/xen_unified.c,v
retrieving revision 1.24
diff -u -p -r1.24 xen_unified.c
--- src/xen_unified.c	15 Oct 2007 21:38:56 -0000	1.24
+++ src/xen_unified.c	16 Oct 2007 14:38:47 -0000
@@ -1054,6 +1054,29 @@ xenUnifiedDomainInterfaceStats (virDomai
 }
 
 static int
+xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path,
+                           long long offset, size_t size,
+                           void *buffer)
+{
+    int r;
+    GET_PRIVATE (dom->conn);
+
+    if (priv->opened[XEN_UNIFIED_XEND_OFFSET]) {
+        r = xenDaemonDomainBlockPeek (dom, path, offset, size, buffer);
+        if (r != -2) return r;
+        /* r == -2 means declined, so fall through to XM driver ... */
+    }
+
+    if (priv->opened[XEN_UNIFIED_XM_OFFSET]) {
+        if (xenXMDomainBlockPeek (dom, path, offset, size, buffer) == 0)
+            return 0;
+    }
+
+    xenUnifiedError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+}
+
+static int
 xenUnifiedNodeGetCellsFreeMemory (virConnectPtr conn, unsigned long long *freeMems,
                                   int startCell, int maxCells)
 {
@@ -1146,6 +1169,7 @@ static virDriver xenUnifiedDriver = {
     .domainMigrateFinish		= xenUnifiedDomainMigrateFinish,
     .domainBlockStats	= xenUnifiedDomainBlockStats,
     .domainInterfaceStats = xenUnifiedDomainInterfaceStats,
+    .domainBlockPeek	= xenUnifiedDomainBlockPeek,
     .nodeGetCellsFreeMemory = xenUnifiedNodeGetCellsFreeMemory,
     .getFreeMemory = xenUnifiedNodeGetFreeMemory,
 };
Index: src/xend_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.c,v
retrieving revision 1.148
diff -u -p -r1.148 xend_internal.c
--- src/xend_internal.c	15 Oct 2007 21:38:56 -0000	1.148
+++ src/xend_internal.c	16 Oct 2007 14:38:49 -0000
@@ -10,6 +10,8 @@
  *  archive for more details.
  */
 
+#define _LARGEFILE64_SOURCE     /* For lseek64 */
+
 #ifdef WITH_XEN
 #include "config.h"
 
@@ -18,6 +20,8 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 #include <sys/errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
@@ -39,6 +43,7 @@
 #include "sexpr.h"
 #include "xml.h"
 #include "buf.h"
+#include "util.h"
 #include "uuid.h"
 #include "xen_unified.h"
 #include "xend_internal.h"
@@ -1334,6 +1339,213 @@ xend_parse_sexp_desc_os(virConnectPtr xe
     return(0);
 }
 
+typedef int
+  (*sexp_blockdevs_cb)
+  (virConnectPtr conn, void *data,
+   int isBlock, int cdrom, int isNoSrcCdrom,
+   char *drvName, char *drvType,
+   const char *src, const char *dst,
+   const char *mode);
+
+/**
+ * xend_parse_sexp_blockdevs:
+ * @conn: connection
+ * @root: root sexpr
+ * @xendConfigVersion: version of xend
+ * @fn: callback function
+ * @data: optional data for callback function
+ *
+ * This parses out block devices from the domain sexpr and calls
+ * fn (conn, data, ...) for each block device found.
+ *
+ * Returns 0 if successful or -1 if failed.
+ */
+static int
+xend_parse_sexp_blockdevs (virConnectPtr conn, struct sexpr *root,
+                           int xendConfigVersion,
+                           sexp_blockdevs_cb fn, void *data)
+{
+    struct sexpr *cur, *node;
+    int hvm;
+
+    hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0;
+
+    for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
+        node = cur->u.s.car;
+        /* Normally disks are in a (device (vbd ...)) block
+           but blktap disks ended up in a differently named
+           (device (tap ....)) block.... */
+        if (sexpr_lookup(node, "device/vbd") ||
+            sexpr_lookup(node, "device/tap")) {
+            char *offset;
+            int ret = -1;
+            int isBlock = 0;
+            int cdrom = 0;
+            int isNoSrcCdrom = 0;
+            char *drvName = NULL;
+            char *drvType = NULL;
+            const char *src = NULL;
+            const char *dst = NULL;
+            const char *mode = NULL;
+
+            /* Again dealing with (vbd...) vs (tap ...) differences */
+            if (sexpr_lookup(node, "device/vbd")) {
+                src = sexpr_node(node, "device/vbd/uname");
+                dst = sexpr_node(node, "device/vbd/dev");
+                mode = sexpr_node(node, "device/vbd/mode");
+            } else {
+                src = sexpr_node(node, "device/tap/uname");
+                dst = sexpr_node(node, "device/tap/dev");
+                mode = sexpr_node(node, "device/tap/mode");
+            }
+
+            if (dst == NULL) {
+                virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                             _("domain information incomplete, vbd has no dev"));
+                goto bad_parse;
+            }
+
+            if (src == NULL) {
+                /* There is a case without the uname to the CD-ROM device */
+                offset = strchr(dst, ':');
+                if (offset) {
+                    if (hvm && !strcmp( offset , ":cdrom")) {
+                        isNoSrcCdrom = 1;
+                    }
+                    offset[0] = '\0';
+                }
+                if (!isNoSrcCdrom) {
+                    virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 _("domain information incomplete, vbd has no src"));
+                    goto bad_parse;
+                }
+            }
+
+            if (!isNoSrcCdrom) {
+                offset = strchr(src, ':');
+                if (!offset) {
+                    virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 _("cannot parse vbd filename, missing driver name"));
+                    goto bad_parse;
+                }
+
+                drvName = malloc((offset-src)+1);
+                if (!drvName) {
+                    virXendError(conn, VIR_ERR_NO_MEMORY,
+                                 _("allocate new buffer"));
+                    goto bad_parse;
+                }
+                strncpy(drvName, src, (offset-src));
+                drvName[offset-src] = '\0';
+
+                src = offset + 1;
+
+                if (!strcmp(drvName, "tap")) {
+                    offset = strchr(src, ':');
+                    if (!offset) {
+                        virXendError(conn, VIR_ERR_INTERNAL_ERROR,
+                                     _("cannot parse vbd filename, missing driver type"));
+                        goto bad_parse;
+                    }
+
+                    drvType = malloc((offset-src)+1);
+                    if (!drvType) {
+                        virXendError(conn, VIR_ERR_NO_MEMORY,
+                                     _("allocate new buffer"));
+                        goto bad_parse;
+                    }
+                    strncpy(drvType, src, (offset-src));
+                    drvType[offset-src] = '\0';
+                    src = offset + 1;
+                    /* Its possible to use blktap driver for block devs
+                       too, but kinda pointless because blkback is better,
+                       so we assume common case here. If blktap becomes
+                       omnipotent, we can revisit this, perhaps stat()'ing
+                       the src file in question */
+                    isBlock = 0;
+                } else if (!strcmp(drvName, "phy")) {
+                    isBlock = 1;
+                } else if (!strcmp(drvName, "file")) {
+                    isBlock = 0;
+                }
+            }
+
+            if (!strncmp(dst, "ioemu:", 6))
+                dst += 6;
+
+            /* New style disk config from Xen >= 3.0.3 */
+            if (xendConfigVersion > 1) {
+                offset = strrchr(dst, ':');
+                if (offset) {
+                    if (!strcmp(offset, ":cdrom")) {
+                        cdrom = 1;
+                    } else if (!strcmp(offset, ":disk")) {
+                        /* The default anyway */
+                    } else {
+                        /* Unknown, lets pretend its a disk too */
+                    }
+                    offset[0] = '\0';
+                }
+            }
+
+            /* Call the callback function. */
+            ret = fn (conn, data, isBlock, cdrom, isNoSrcCdrom,
+                      drvName, drvType, src, dst, mode);
+
+        bad_parse:
+            if (drvName)
+                free(drvName);
+            if (drvType)
+                free(drvType);
+
+            if (ret == -1) return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int
+xend_parse_sexp_desc_blockdev (virConnectPtr conn ATTRIBUTE_UNUSED,
+                               void *data,
+                               int isBlock, int cdrom, int isNoSrcCdrom,
+                               char *drvName, char *drvType,
+                               const char *src, const char *dst,
+                               const char *mode)
+{
+    virBuffer *buf = (virBuffer *) data;
+
+    if (!isNoSrcCdrom) {
+        virBufferVSprintf(buf, "    <disk type='%s' device='%s'>\n",
+                          isBlock ? "block" : "file",
+                          cdrom ? "cdrom" : "disk");
+        if (drvType) {
+            virBufferVSprintf(buf, "      <driver name='%s' type='%s'/>\n", drvName, drvType);
+        } else {
+            virBufferVSprintf(buf, "      <driver name='%s'/>\n", drvName);
+        }
+        if (isBlock) {
+            virBufferVSprintf(buf, "      <source dev='%s'/>\n", src);
+        } else {
+            virBufferVSprintf(buf, "      <source file='%s'/>\n", src);
+        }
+    } else {
+        /* This case is the cdrom device only */
+        virBufferVSprintf(buf, "    <disk device='cdrom'>\n");
+    }
+    virBufferVSprintf(buf, "      <target dev='%s'/>\n", dst);
+
+    /* XXX should we force mode == r, if cdrom==1, or assume
+       xend has already done this ? */
+    if ((mode != NULL) && (!strcmp(mode, "r")))
+        virBufferVSprintf(buf, "      <readonly/>\n");
+    else if ((mode != NULL) && (!strcmp(mode, "w!")))
+        virBufferVSprintf(buf, "      <shareable/>\n");
+    virBufferAdd(buf, "    </disk>\n", 12);
+
+    return 0;
+}
+
 /**
  * xend_parse_sexp_desc:
  * @conn: the connection associated with the XML
@@ -1470,158 +1682,16 @@ xend_parse_sexp_desc(virConnectPtr conn,
     if ((tmp != NULL) && (tmp[0] != 0))
         virBufferVSprintf(&buf, "    <emulator>%s</emulator>\n", tmp);
 
+    /* append block devices */
+    if (xend_parse_sexp_blockdevs (conn, root, xendConfigVersion,
+                                   xend_parse_sexp_desc_blockdev, &buf) == -1)
+        goto error;
+
+    /* append network devices and framebuffer */
     for (cur = root; cur->kind == SEXPR_CONS; cur = cur->u.s.cdr) {
         node = cur->u.s.car;
-        /* Normally disks are in a (device (vbd ...)) block
-           but blktap disks ended up in a differently named
-           (device (tap ....)) block.... */
-        if (sexpr_lookup(node, "device/vbd") ||
-            sexpr_lookup(node, "device/tap")) {
-            char *offset;
-            int isBlock = 0;
-            int cdrom = 0;
-            int isNoSrcCdrom = 0;
-            char *drvName = NULL;
-            char *drvType = NULL;
-            const char *src = NULL;
-            const char *dst = NULL;
-            const char *mode = NULL;
-
-            /* Again dealing with (vbd...) vs (tap ...) differences */
-            if (sexpr_lookup(node, "device/vbd")) {
-                src = sexpr_node(node, "device/vbd/uname");
-                dst = sexpr_node(node, "device/vbd/dev");
-                mode = sexpr_node(node, "device/vbd/mode");
-            } else {
-                src = sexpr_node(node, "device/tap/uname");
-                dst = sexpr_node(node, "device/tap/dev");
-                mode = sexpr_node(node, "device/tap/mode");
-            }
-
-            if (dst == NULL) {
-                virXendError(conn, VIR_ERR_INTERNAL_ERROR,
-                             _("domain information incomplete, vbd has no dev"));
-                goto bad_parse;
-            }
-
-            if (src == NULL) {
-                /* There is a case without the uname to the CD-ROM device */
-                offset = strchr(dst, ':');
-                if (offset) {
-                    if (hvm && !strcmp( offset , ":cdrom")) {
-                        isNoSrcCdrom = 1;
-                    }
-                    offset[0] = '\0';
-                }
-                if (!isNoSrcCdrom) {
-                    virXendError(conn, VIR_ERR_INTERNAL_ERROR,
-                                 _("domain information incomplete, vbd has no src"));
-                    goto bad_parse;
-                }
-            }
-
-            if (!isNoSrcCdrom) {
-                offset = strchr(src, ':');
-                if (!offset) {
-                    virXendError(conn, VIR_ERR_INTERNAL_ERROR,
-                                 _("cannot parse vbd filename, missing driver name"));
-                    goto bad_parse;
-                }
-
-                drvName = malloc((offset-src)+1);
-                if (!drvName) {
-                    virXendError(conn, VIR_ERR_NO_MEMORY,
-                                 _("allocate new buffer"));
-                    goto bad_parse;
-                }
-                strncpy(drvName, src, (offset-src));
-                drvName[offset-src] = '\0';
-
-                src = offset + 1;
-
-                if (!strcmp(drvName, "tap")) {
-                    offset = strchr(src, ':');
-                    if (!offset) {
-                        virXendError(conn, VIR_ERR_INTERNAL_ERROR,
-                                     _("cannot parse vbd filename, missing driver type"));
-                        goto bad_parse;
-                    }
-
-                    drvType = malloc((offset-src)+1);
-                    if (!drvType) {
-                        virXendError(conn, VIR_ERR_NO_MEMORY,
-                                     _("allocate new buffer"));
-                        goto bad_parse;
-                    }
-                    strncpy(drvType, src, (offset-src));
-                    drvType[offset-src] = '\0';
-                    src = offset + 1;
-                    /* Its possible to use blktap driver for block devs
-                       too, but kinda pointless because blkback is better,
-                       so we assume common case here. If blktap becomes
-                       omnipotent, we can revisit this, perhaps stat()'ing
-                       the src file in question */
-                    isBlock = 0;
-                } else if (!strcmp(drvName, "phy")) {
-                    isBlock = 1;
-                } else if (!strcmp(drvName, "file")) {
-                    isBlock = 0;
-                }
-            }
-
-            if (!strncmp(dst, "ioemu:", 6))
-                dst += 6;
-
-            /* New style disk config from Xen >= 3.0.3 */
-            if (xendConfigVersion > 1) {
-                offset = strrchr(dst, ':');
-                if (offset) {
-                    if (!strcmp(offset, ":cdrom")) {
-                        cdrom = 1;
-                    } else if (!strcmp(offset, ":disk")) {
-                        /* The default anyway */
-                    } else {
-                        /* Unknown, lets pretend its a disk too */
-                    }
-                    offset[0] = '\0';
-                }
-            }
 
-            if (!isNoSrcCdrom) {
-                virBufferVSprintf(&buf, "    <disk type='%s' device='%s'>\n",
-                                  isBlock ? "block" : "file",
-                                  cdrom ? "cdrom" : "disk");
-                if (drvType) {
-                    virBufferVSprintf(&buf, "      <driver name='%s' type='%s'/>\n", drvName, drvType);
-                } else {
-                    virBufferVSprintf(&buf, "      <driver name='%s'/>\n", drvName);
-                }
-                if (isBlock) {
-                    virBufferVSprintf(&buf, "      <source dev='%s'/>\n", src);
-                } else {
-                    virBufferVSprintf(&buf, "      <source file='%s'/>\n", src);
-                }
-            } else {
-                /* This case is the cdrom device only */
-                virBufferVSprintf(&buf, "    <disk device='cdrom'>\n");
-            }
-            virBufferVSprintf(&buf, "      <target dev='%s'/>\n", dst);
-
-
-            /* XXX should we force mode == r, if cdrom==1, or assume
-               xend has already done this ? */
-            if ((mode != NULL) && (!strcmp(mode, "r")))
-                virBufferVSprintf(&buf, "      <readonly/>\n");
-	    else if ((mode != NULL) && (!strcmp(mode, "w!")))
-                virBufferVSprintf(&buf, "      <shareable/>\n");
-            virBufferAdd(&buf, "    </disk>\n", 12);
-
-            bad_parse:
-            if (drvName)
-                free(drvName);
-            if (drvType)
-                free(drvType);
-        } else if (sexpr_lookup(node, "device/vif")) {
+        if (sexpr_lookup(node, "device/vif")) {
             const char *tmp2;
             tmp2 = sexpr_node(node, "device/vif/script");
             tmp = sexpr_node(node, "device/vif/bridge");
@@ -3734,6 +3804,121 @@ error:
     return(ret);
 }
 
+struct check_path_data {
+    const char *path;
+    int ok;
+};
+
+static int
+check_path (virConnectPtr conn ATTRIBUTE_UNUSED, void *vp,
+            int isBlock ATTRIBUTE_UNUSED,
+            int cdrom, int isNoSrcCdrom,
+            char *drvName ATTRIBUTE_UNUSED, char *drvType ATTRIBUTE_UNUSED,
+            const char *src, const char *dst ATTRIBUTE_UNUSED,
+            const char *mode ATTRIBUTE_UNUSED)
+{
+    struct check_path_data *data = (struct check_path_data *) vp;
+
+    if (!isNoSrcCdrom && !cdrom && src && STREQ (src, data->path))
+        data->ok = 1;
+
+    return 0;
+}
+
+/**
+ * xenDaemonDomainBlockPeek:
+ * @dom: domain object
+ * @path: path to the file or device
+ * @offset: offset
+ * @size: size
+ * @buffer: return buffer
+ *
+ * Returns 0 if successful, -1 if error, -2 if declined.
+ */
+int
+xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path,
+                          long long offset, size_t size,
+                          void *buffer)
+{
+    xenUnifiedPrivatePtr priv;
+    struct sexpr *root;
+    struct check_path_data data;
+    int fd, ret = -1;
+    struct stat statbuf;
+
+    priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
+
+    if (domain->id < 0 && priv->xendConfigVersion < 3)
+        return -2;              /* Decline, allow XM to handle it. */
+
+    /* Security check: The path must correspond to a block device. */
+    if (domain->id > 0)
+        root = sexpr_get (domain->conn, "/xend/domain/%d?detail=1",
+                          domain->id);
+    else if (domain->id < 0)
+        root = sexpr_get (domain->conn, "/xend/domain/%s?detail=1",
+                          domain->name);
+    else {
+        /* This call always fails for dom0. */
+        virXendError (domain->conn, VIR_ERR_NO_SUPPORT,
+                      "domainBlockPeek is not supported for dom0");
+        return -1;
+    }
+
+    if (!root) {
+        virXendError (domain->conn, VIR_ERR_XEN_CALL, __FUNCTION__);
+        return -1;
+    }
+
+    data.path = path;
+    data.ok = 0;
+
+    if (xend_parse_sexp_blockdevs (domain->conn, root,
+                                   priv->xendConfigVersion,
+                                   check_path, &data) == -1)
+        return -1;
+
+    if (!data.ok) {
+        virXendError (domain->conn, VIR_ERR_INVALID_ARG, "path");
+        return -1;
+    }
+
+    /* The path is correct, now try to open it and get its size. */
+    fd = open (path, O_RDONLY);
+    if (fd == -1 || fstat (fd, &statbuf) == -1) {
+        virXendError (domain->conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+        goto done;
+    }
+
+    /* XXX The following test fails for LVM devices for a couple
+     * of reasons: (1) They are commonly symlinks to /dev/mapper/foo
+     * and despite the man page for fstat, fstat stats the link not
+     * the file.  (2) Stat even on the block device returns st_size==0.
+     *
+     * Anyhow, it should be safe to ignore this test since we are
+     * in O_RDONLY mode.
+     */
+#if 0
+    /* NB we know offset > 0, size >= 0 */
+    if (offset + size > statbuf.st_size) {
+        virXendError (domain->conn, VIR_ERR_INVALID_ARG, "offset");
+        goto done;
+    }
+#endif
+
+    /* Seek and read. */
+    if (lseek64 (fd, offset, SEEK_SET) == (off64_t) -1 ||
+        saferead (fd, buffer, size) == (ssize_t) -1) {
+        virXendError (domain->conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+        goto done;
+    }
+
+    ret = 0;
+ done:
+    if (fd >= 0) close (fd);
+    return ret;
+}
+
 #endif /* ! PROXY */
 #endif /* WITH_XEN */
 
Index: src/xend_internal.h
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.h,v
retrieving revision 1.34
diff -u -p -r1.34 xend_internal.h
--- src/xend_internal.h	30 Sep 2007 13:09:07 -0000	1.34
+++ src/xend_internal.h	16 Oct 2007 14:38:49 -0000
@@ -226,6 +226,8 @@ virDomainPtr xenDaemonLookupByName(virCo
 int xenDaemonDomainMigratePrepare (virConnectPtr dconn, char **cookie, int *cookielen, const char *uri_in, char **uri_out, unsigned long flags, const char *dname, unsigned long resource);
 int xenDaemonDomainMigratePerform (virDomainPtr domain, const char *cookie, int cookielen, const char *uri, unsigned long flags, const char *dname, unsigned long resource);
 
+int xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, long long offset, size_t size, void *buffer);
+
 #ifdef __cplusplus
 }
 #endif
Index: src/xm_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xm_internal.c,v
retrieving revision 1.41
diff -u -p -r1.41 xm_internal.c
--- src/xm_internal.c	10 Oct 2007 17:55:38 -0000	1.41
+++ src/xm_internal.c	16 Oct 2007 14:38:51 -0000
@@ -2373,6 +2373,17 @@ int xenXMNumOfDefinedDomains(virConnectP
     return virHashSize(nameConfigMap);
 }
 
+int
+xenXMDomainBlockPeek (virDomainPtr dom,
+                      const char *path ATTRIBUTE_UNUSED,
+                      long long offset ATTRIBUTE_UNUSED,
+                      size_t size ATTRIBUTE_UNUSED,
+                      void *buffer ATTRIBUTE_UNUSED)
+{
+    xenXMError (dom->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+}
+
 #endif /* WITH_XEN */
 /*
  * Local variables:
Index: src/xm_internal.h
===================================================================
RCS file: /data/cvs/libvirt/src/xm_internal.h,v
retrieving revision 1.5
diff -u -p -r1.5 xm_internal.h
--- src/xm_internal.h	6 Jul 2007 15:11:22 -0000	1.5
+++ src/xm_internal.h	16 Oct 2007 14:38:51 -0000
@@ -58,6 +58,7 @@ int xenXMDomainUndefine(virDomainPtr dom
 
 virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml);
 char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf);
+int xenXMDomainBlockPeek (virDomainPtr dom, const char *path, long long offset, size_t size, void *buffer);
 
 #ifdef __cplusplus
 }
Index: tests/sexpr2xmldata/sexpr2xml-curmem.xml
===================================================================
RCS file: /data/cvs/libvirt/tests/sexpr2xmldata/sexpr2xml-curmem.xml,v
retrieving revision 1.4
diff -u -p -r1.4 sexpr2xml-curmem.xml
--- tests/sexpr2xmldata/sexpr2xml-curmem.xml	21 Aug 2007 08:54:07 -0000	1.4
+++ tests/sexpr2xmldata/sexpr2xml-curmem.xml	16 Oct 2007 14:38:51 -0000
@@ -15,17 +15,17 @@
   <on_reboot>restart</on_reboot>
   <on_crash>restart</on_crash>
   <devices>
+    <disk type='file' device='disk'>
+      <driver name='tap' type='aio'/>
+      <source file='/xen/rhel5.img'/>
+      <target dev='xvda:disk'/>
+    </disk>
     <interface type='bridge'>
       <source bridge='xenbr0'/>
       <target dev='vif5.0'/>
       <mac address='00:16:3e:1d:06:15'/>
       <script path='vif-bridge'/>
     </interface>
-    <disk type='file' device='disk'>
-      <driver name='tap' type='aio'/>
-      <source file='/xen/rhel5.img'/>
-      <target dev='xvda:disk'/>
-    </disk>
     <input type='mouse' bus='xen'/>
     <graphics type='vnc' port='5905'/>
   </devices>
Index: tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml
===================================================================
RCS file: /data/cvs/libvirt/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml,v
retrieving revision 1.8
diff -u -p -r1.8 sexpr2xml-no-source-cdrom.xml
--- tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml	30 Sep 2007 15:36:47 -0000	1.8
+++ tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml	16 Oct 2007 14:38:51 -0000
@@ -20,11 +20,6 @@
   <clock offset='utc'/>
   <devices>
     <emulator>/usr/lib/xen/bin/qemu-dm</emulator>
-    <interface type='bridge'>
-      <source bridge='xenbr0'/>
-      <target dev='vif6.0'/>
-      <mac address='00:16:3e:0a:7b:39'/>
-    </interface>
     <disk type='block' device='disk'>
       <driver name='phy'/>
       <source dev='/dev/sda8'/>
@@ -34,6 +29,11 @@
       <target dev='hdc'/>
       <readonly/>
     </disk>
+    <interface type='bridge'>
+      <source bridge='xenbr0'/>
+      <target dev='vif6.0'/>
+      <mac address='00:16:3e:0a:7b:39'/>
+    </interface>
     <input type='mouse' bus='ps2'/>
     <graphics type='vnc' port='5906'/>
   </devices>

Attachment: smime.p7s
Description: S/MIME Cryptographic Signature


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]