Index: configure.in =================================================================== RCS file: /data/cvs/libvirt/configure.in,v retrieving revision 1.151 diff -b -u -p -r1.151 configure.in --- configure.in 29 May 2008 19:27:04 -0000 1.151 +++ configure.in 4 Jun 2008 15:08:08 -0000 @@ -60,6 +60,10 @@ AM_PROG_CC_C_O LIBVIRT_COMPILE_WARNINGS([maximum]) +dnl Support large files / 64 bit seek offsets. +dnl Use --disable-largefile if you don't want this. +AC_SYS_LARGEFILE + dnl Availability of various common functions (non-fatal if missing). AC_CHECK_FUNCS([cfmakeraw regexec uname sched_getaffinity]) @@ -982,8 +986,6 @@ AC_SUBST([CYGWIN_EXTRA_LIBADD]) AC_SUBST([CYGWIN_EXTRA_PYTHON_LIBADD]) AC_SUBST([MINGW_EXTRA_LDFLAGS]) -AC_SYS_LARGEFILE - # Set LV_LIBTOOL_OBJDIR to "." or $lt_cv_objdir, depending on whether # we're building shared libraries. This is the name of the directory # in which .o files will be created. Index: include/libvirt/libvirt.h =================================================================== RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h,v retrieving revision 1.74 diff -b -u -p -r1.74 libvirt.h --- include/libvirt/libvirt.h 23 May 2008 08:32:08 -0000 1.74 +++ include/libvirt/libvirt.h 4 Jun 2008 15:08:10 -0000 @@ -530,7 +530,11 @@ int virDomainInterfa const char *path, virDomainInterfaceStatsPtr stats, size_t size); - +int virDomainBlockPeek (virDomainPtr dom, + const char *path, + unsigned 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.49 diff -b -u -p -r1.49 libvirt.h.in --- include/libvirt/libvirt.h.in 23 May 2008 08:32:08 -0000 1.49 +++ include/libvirt/libvirt.h.in 4 Jun 2008 15:08:10 -0000 @@ -530,7 +530,11 @@ int virDomainInterfa const char *path, virDomainInterfaceStatsPtr stats, size_t size); - +int virDomainBlockPeek (virDomainPtr dom, + const char *path, + unsigned 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.47 diff -b -u -p -r1.47 driver.h --- src/driver.h 13 May 2008 06:30:58 -0000 1.47 +++ src/driver.h 4 Jun 2008 15:08:11 -0000 @@ -226,6 +226,13 @@ typedef int struct _virDomainInterfaceStats *stats); typedef int + (*virDrvDomainBlockPeek) + (virDomainPtr domain, + const char *path, + unsigned long long offset, size_t size, + void *buffer); + +typedef int (*virDrvDomainMigratePrepare) (virConnectPtr dconn, char **cookie, @@ -337,6 +344,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.143 diff -b -u -p -r1.143 libvirt.c --- src/libvirt.c 29 May 2008 19:23:17 -0000 1.143 +++ src/libvirt.c 4 Jun 2008 15:08:14 -0000 @@ -2586,7 +2586,73 @@ 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 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, + unsigned 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 (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.40 diff -b -u -p -r1.40 libvirt_sym.version --- src/libvirt_sym.version 13 May 2008 06:30:58 -0000 1.40 +++ src/libvirt_sym.version 4 Jun 2008 15:08:14 -0000 @@ -73,6 +73,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.82 diff -b -u -p -r1.82 qemu_driver.c --- src/qemu_driver.c 29 May 2008 19:20:23 -0000 1.82 +++ src/qemu_driver.c 4 Jun 2008 15:08:17 -0000 @@ -3521,6 +3521,7 @@ static virDriver qemuDriver = { NULL, /* domainMigrateFinish */ qemudDomainBlockStats, /* domainBlockStats */ qemudDomainInterfaceStats, /* domainInterfaceStats */ + NULL, /* domainBlockPeek */ #if HAVE_NUMACTL qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ qemudNodeGetFreeMemory, /* getFreeMemory */ Index: src/test.c =================================================================== RCS file: /data/cvs/libvirt/src/test.c,v retrieving revision 1.75 diff -b -u -p -r1.75 test.c --- src/test.c 29 May 2008 19:20:23 -0000 1.75 +++ src/test.c 4 Jun 2008 15:08:18 -0000 @@ -2060,6 +2060,7 @@ static virDriver testDriver = { NULL, /* domainMigrateFinish */ NULL, /* domainBlockStats */ NULL, /* domainInterfaceStats */ + NULL, /* domainBlockPeek */ testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ NULL, /* getFreeMemory */ }; Index: src/xen_unified.c =================================================================== RCS file: /data/cvs/libvirt/src/xen_unified.c,v retrieving revision 1.44 diff -b -u -p -r1.44 xen_unified.c --- src/xen_unified.c 14 May 2008 19:51:24 -0000 1.44 +++ src/xen_unified.c 4 Jun 2008 15:08:19 -0000 @@ -1235,6 +1235,29 @@ xenUnifiedDomainInterfaceStats (virDomai } static int +xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path, + unsigned 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) { @@ -1329,6 +1352,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.194 diff -b -u -p -r1.194 xend_internal.c --- src/xend_internal.c 29 May 2008 19:20:23 -0000 1.194 +++ src/xend_internal.c 4 Jun 2008 15:08:22 -0000 @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -1705,6 +1707,219 @@ error: return ret; } +typedef int + (*sexp_blockdevs_cb) + (virConnectPtr conn, void *data, + int isBlock, int cdrom, int isNoSrcCdrom, int hvm, + const char *drvName, const 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 && STREQ(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; + } + + if (VIR_ALLOC_N(drvName, (offset-src)+1) < 0) { + 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 (STREQ (drvName, "tap")) { + offset = strchr(src, ':'); + if (!offset) { + virXendError(conn, VIR_ERR_INTERNAL_ERROR, + _("cannot parse vbd filename, missing driver type")); + goto bad_parse; + } + + if (VIR_ALLOC_N(drvType, (offset-src)+1)< 0) { + 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 (STREQ(drvName, "phy")) { + isBlock = 1; + } else if (STREQ(drvName, "file")) { + isBlock = 0; + } + } + + if (STREQLEN (dst, "ioemu:", 6)) + dst += 6; + + /* New style disk config from Xen >= 3.0.3 */ + if (xendConfigVersion > 1) { + offset = strrchr(dst, ':'); + if (offset) { + if (STREQ (offset, ":cdrom")) { + cdrom = 1; + } else if (STREQ (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, hvm, + drvName, drvType, src, dst, mode); + + bad_parse: + VIR_FREE(drvName); + VIR_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, + int hvm, + const char *drvName, const char *drvType, + const char *src, const char *dst, + const char *mode) +{ + virBuffer *buf = (virBuffer *) data; + const char *bus = NULL; + + if (!isNoSrcCdrom) { + virBufferVSprintf(buf, " \n", + isBlock ? "block" : "file", + cdrom ? "cdrom" : "disk"); + if (drvType) { + virBufferVSprintf(buf, " \n", drvName, drvType); + } else { + virBufferVSprintf(buf, " \n", drvName); + } + if (isBlock) { + virBufferVSprintf(buf, " \n", src); + } else { + virBufferVSprintf(buf, " \n", src); + } + } else { + /* This case is the cdrom device only */ + virBufferAddLit(buf, " \n"); + } + if (STRPREFIX(dst, "xvd") || !hvm) { + bus = "xen"; + } else if (STRPREFIX(dst, "sd")) { + bus = "scsi"; + } else { + bus = "ide"; + } + virBufferVSprintf(buf, " \n", + dst, bus); + + /* XXX should we force mode == r, if cdrom==1, or assume + xend has already done this ? */ + if ((mode != NULL) && (STREQ (mode, "r"))) + virBufferAddLit(buf, " \n"); + else if ((mode != NULL) && (STREQ (mode, "w!"))) + virBufferAddLit(buf, " \n"); + virBufferAddLit(buf, " \n"); + + return 0; +} + /** * xend_parse_sexp_desc: * @conn: the connection associated with the XML @@ -1849,164 +2064,15 @@ xend_parse_sexp_desc(virConnectPtr conn, if ((tmp != NULL) && (tmp[0] != 0)) virBufferVSprintf(&buf, " %s\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; - const char *bus = 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 && STREQ( 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; - } - - if (VIR_ALLOC_N(drvName, (offset-src)+1) < 0) { - 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 (STREQ(drvName, "tap")) { - offset = strchr(src, ':'); - if (!offset) { - virXendError(conn, VIR_ERR_INTERNAL_ERROR, - _("cannot parse vbd filename, missing driver type")); - goto bad_parse; - } - - if (VIR_ALLOC_N(drvType, (offset-src)+1)< 0) { - 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 (STREQ(drvName, "phy")) { - isBlock = 1; - } else if (STREQ(drvName, "file")) { - isBlock = 0; - } - } - - if (STRPREFIX(dst, "ioemu:")) - dst += 6; - - /* New style disk config from Xen >= 3.0.3 */ - if (xendConfigVersion > 1) { - offset = strrchr(dst, ':'); - if (offset) { - if (STREQ(offset, ":cdrom")) { - cdrom = 1; - } else if (STREQ(offset, ":disk")) { - /* The default anyway */ - } else { - /* Unknown, lets pretend its a disk too */ - } - offset[0] = '\0'; - } - } - - if (!isNoSrcCdrom) { - virBufferVSprintf(&buf, " \n", - isBlock ? "block" : "file", - cdrom ? "cdrom" : "disk"); - if (drvType) { - virBufferVSprintf(&buf, " \n", drvName, drvType); - } else { - virBufferVSprintf(&buf, " \n", drvName); - } - if (isBlock) { - virBufferVSprintf(&buf, " \n", src); - } else { - virBufferVSprintf(&buf, " \n", src); - } - } else { - /* This case is the cdrom device only */ - virBufferAddLit(&buf, " \n"); - } - - if (STRPREFIX(dst, "xvd") || !hvm) { - bus = "xen"; - } else if (STRPREFIX(dst, "sd")) { - bus = "scsi"; - } else { - bus = "ide"; - } - virBufferVSprintf(&buf, " \n", - dst, bus); - - - /* XXX should we force mode == r, if cdrom==1, or assume - xend has already done this ? */ - if ((mode != NULL) && (STREQ(mode, "r"))) - virBufferAddLit(&buf, " \n"); - else if ((mode != NULL) && (STREQ(mode, "w!"))) - virBufferAddLit(&buf, " \n"); - virBufferAddLit(&buf, " \n"); - - bad_parse: - VIR_FREE(drvName); - VIR_FREE(drvType); - } else if (sexpr_lookup(node, "device/vif")) { + if (sexpr_lookup(node, "device/vif")) { const char *tmp2, *model; tmp2 = sexpr_node(node, "device/vif/script"); tmp = sexpr_node(node, "device/vif/bridge"); @@ -4433,5 +4499,110 @@ 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, + int hvm ATTRIBUTE_UNUSED, + const char *drvName ATTRIBUTE_UNUSED, + const 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, + unsigned 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, + _("invalid 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; + } + + /* Seek and read. */ + /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should + * be 64 bits on all platforms. + */ + if (lseek (fd, offset, SEEK_SET) == (off_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.43 diff -b -u -p -r1.43 xend_internal.h --- src/xend_internal.h 9 May 2008 08:17:19 -0000 1.43 +++ src/xend_internal.h 4 Jun 2008 15:08:22 -0000 @@ -244,6 +244,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, unsigned 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.80 diff -b -u -p -r1.80 xm_internal.c --- src/xm_internal.c 3 Jun 2008 08:01:45 -0000 1.80 +++ src/xm_internal.c 4 Jun 2008 15:08:24 -0000 @@ -3241,4 +3241,15 @@ xenXMDomainDetachDevice(virDomainPtr dom return (ret); } +int +xenXMDomainBlockPeek (virDomainPtr dom, + const char *path ATTRIBUTE_UNUSED, + unsigned 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 */ Index: src/xm_internal.h =================================================================== RCS file: /data/cvs/libvirt/src/xm_internal.h,v retrieving revision 1.11 diff -b -u -p -r1.11 xm_internal.h --- src/xm_internal.h 10 Apr 2008 16:54:54 -0000 1.11 +++ src/xm_internal.h 4 Jun 2008 15:08:24 -0000 @@ -60,6 +60,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, unsigned 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.6 diff -b -u -p -r1.6 sexpr2xml-curmem.xml --- tests/sexpr2xmldata/sexpr2xml-curmem.xml 8 May 2008 14:41:56 -0000 1.6 +++ tests/sexpr2xmldata/sexpr2xml-curmem.xml 4 Jun 2008 15:08:24 -0000 @@ -15,17 +15,17 @@ restart restart + + + + +