? scripts/Makefile ? scripts/Makefile.in Index: qemud/remote.c =================================================================== RCS file: /data/cvs/libvirt/qemud/remote.c,v retrieving revision 1.35 diff -u -r1.35 remote.c --- qemud/remote.c 23 May 2008 08:24:44 -0000 1.35 +++ qemud/remote.c 5 Jun 2008 18:43:10 -0000 @@ -890,6 +890,54 @@ } static int +remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_domain_block_peek_args *args, + remote_domain_block_peek_ret *ret) +{ + virDomainPtr dom; + char *path; + unsigned long long offset; + size_t size; + unsigned int flags; + CHECK_CONN (client); + + dom = get_nonnull_domain (client->conn, args->dom); + if (dom == NULL) { + remoteDispatchError (client, req, "%s", _("domain not found")); + return -2; + } + path = args->path; + offset = args->offset; + size = args->size; + flags = args->flags; + + if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) { + remoteDispatchError (client, req, + "%s", _("size > maximum buffer size")); + return -2; + } + + ret->buffer.buffer_len = size; + ret->buffer.buffer_val = malloc (size); + if (!ret->buffer.buffer_val) { + remoteDispatchError (client, req, "%s", strerror (errno)); + return -2; + } + + if (virDomainBlockPeek (dom, path, offset, size, + ret->buffer.buffer_val, flags) == -1) { + /* free (ret->buffer.buffer_val); - caller frees */ + virDomainFree (dom); + return -1; + } + virDomainFree (dom); + + return 0; +} + +static int remoteDispatchDomainAttachDevice (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client, remote_message_header *req, Index: qemud/remote_protocol.x =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_protocol.x,v retrieving revision 1.13 diff -u -r1.13 remote_protocol.x --- qemud/remote_protocol.x 23 May 2008 08:24:44 -0000 1.13 +++ qemud/remote_protocol.x 5 Jun 2008 18:43:11 -0000 @@ -96,6 +96,12 @@ /* Maximum number of auth types */ const REMOTE_AUTH_TYPE_LIST_MAX = 20; +/* Maximum length of a block or memory peek buffer message. + * Note applications need to be aware of this limit and issue multiple + * requests for large amounts of data. + */ +const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 65536; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -322,6 +328,18 @@ hyper tx_drop; }; +struct remote_domain_block_peek_args { + remote_nonnull_domain dom; + remote_nonnull_string path; + unsigned hyper offset; + unsigned size; + unsigned flags; +}; + +struct remote_domain_block_peek_ret { + opaque buffer; +}; + struct remote_list_domains_args { int maxids; }; @@ -1036,7 +1054,9 @@ REMOTE_PROC_STORAGE_VOL_GET_PATH = 100, REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101, - REMOTE_PROC_NODE_GET_FREE_MEMORY = 102 + REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, + + REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103 }; /* Custom RPC structure. */ Index: src/driver.h =================================================================== RCS file: /data/cvs/libvirt/src/driver.h,v retrieving revision 1.48 diff -u -r1.48 driver.h --- src/driver.h 5 Jun 2008 13:17:45 -0000 1.48 +++ src/driver.h 5 Jun 2008 18:43:11 -0000 @@ -230,7 +230,8 @@ (virDomainPtr domain, const char *path, unsigned long long offset, size_t size, - void *buffer); + void *buffer, + unsigned int flags); typedef int (*virDrvDomainMigratePrepare) Index: src/libvirt.c =================================================================== RCS file: /data/cvs/libvirt/src/libvirt.c,v retrieving revision 1.144 diff -u -r1.144 libvirt.c --- src/libvirt.c 5 Jun 2008 13:17:45 -0000 1.144 +++ src/libvirt.c 5 Jun 2008 18:43:14 -0000 @@ -2659,7 +2659,8 @@ } if (conn->driver->domainBlockPeek) - return conn->driver->domainBlockPeek (dom, path, offset, size, buffer); + return conn->driver->domainBlockPeek (dom, path, offset, size, + buffer, flags); virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__); return -1; Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.83 diff -u -r1.83 qemu_driver.c --- src/qemu_driver.c 5 Jun 2008 13:17:45 -0000 1.83 +++ src/qemu_driver.c 5 Jun 2008 18:43:17 -0000 @@ -3163,6 +3163,64 @@ #endif } +static int +qemudDomainBlockPeek (virDomainPtr dom, + const char *path, + unsigned long long offset, size_t size, + void *buffer, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID (driver, dom->uuid); + int i; + int fd, ret = -1; + + if (!vm) { + qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid")); + return -1; + } + + if (!path || path[0] == '\0') { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("NULL or empty path")); + return -1; + } + + /* Check the path belongs to this domain. */ + for (i = 0; i < vm->def->ndisks; ++i) { + if (STREQ (vm->def->disks[i].src, path)) goto found; + } + qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("invalid path")); + return -1; + +found: + /* The path is correct, now try to open it and get its size. */ + fd = open (path, O_RDONLY); + if (fd == -1) { + qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR, + "%s", 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) { + qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR, + "%s", strerror (errno)); + goto done; + } + + ret = 0; + done: + if (fd >= 0) close (fd); + return ret; +} + static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED, const unsigned char *uuid) { struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; @@ -3521,7 +3579,7 @@ NULL, /* domainMigrateFinish */ qemudDomainBlockStats, /* domainBlockStats */ qemudDomainInterfaceStats, /* domainInterfaceStats */ - NULL, /* domainBlockPeek */ + qemudDomainBlockPeek, /* domainBlockPeek */ #if HAVE_NUMACTL qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ qemudNodeGetFreeMemory, /* getFreeMemory */ Index: src/remote_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/remote_internal.c,v retrieving revision 1.76 diff -u -r1.76 remote_internal.c --- src/remote_internal.c 22 May 2008 15:20:25 -0000 1.76 +++ src/remote_internal.c 5 Jun 2008 18:43:20 -0000 @@ -2374,6 +2374,52 @@ return 0; } +static int +remoteDomainBlockPeek (virDomainPtr domain, + const char *path, + unsigned long long offset, + size_t size, + void *buffer, + unsigned int flags) +{ + remote_domain_block_peek_args args; + remote_domain_block_peek_ret ret; + GET_PRIVATE (domain->conn, -1); + + if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) { + errorf (domain->conn, VIR_ERR_RPC, + _("block peek request too large for remote protocol, %zi > %d"), + size, REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX); + return -1; + } + + make_nonnull_domain (&args.dom, domain); + args.path = (char *) path; + args.offset = offset; + args.size = size; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_BLOCK_PEEK, + (xdrproc_t) xdr_remote_domain_block_peek_args, + (char *) &args, + (xdrproc_t) xdr_remote_domain_block_peek_ret, + (char *) &ret) == -1) + return -1; + + if (ret.buffer.buffer_len != size) { + errorf (domain->conn, VIR_ERR_RPC, + _("returned buffer is not same size as requested")); + free (ret.buffer.buffer_val); + return -1; + } + + memcpy (buffer, ret.buffer.buffer_val, size); + free (ret.buffer.buffer_val); + + return 0; +} + /*----------------------------------------------------------------------*/ static int @@ -4784,6 +4830,7 @@ .domainMigrateFinish = remoteDomainMigrateFinish, .domainBlockStats = remoteDomainBlockStats, .domainInterfaceStats = remoteDomainInterfaceStats, + .domainBlockPeek = remoteDomainBlockPeek, .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory, .getFreeMemory = remoteNodeGetFreeMemory, }; Index: src/xen_unified.c =================================================================== RCS file: /data/cvs/libvirt/src/xen_unified.c,v retrieving revision 1.45 diff -u -r1.45 xen_unified.c --- src/xen_unified.c 5 Jun 2008 13:17:45 -0000 1.45 +++ src/xen_unified.c 5 Jun 2008 18:43:21 -0000 @@ -1237,7 +1237,7 @@ static int xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path, unsigned long long offset, size_t size, - void *buffer) + void *buffer, unsigned int flags ATTRIBUTE_UNUSED) { int r; GET_PRIVATE (dom->conn); Index: src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.195 diff -u -r1.195 xend_internal.c --- src/xend_internal.c 5 Jun 2008 13:17:45 -0000 1.195 +++ src/xend_internal.c 5 Jun 2008 18:43:24 -0000 @@ -4541,7 +4541,6 @@ struct sexpr *root; struct check_path_data data; int fd, ret = -1; - struct stat statbuf; priv = (xenUnifiedPrivatePtr) domain->conn->privateData; @@ -4583,7 +4582,7 @@ /* 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) { + if (fd == -1) { virXendError (domain->conn, VIR_ERR_SYSTEM_ERROR, strerror (errno)); goto done; }