It fixes: - unnecessary initialisations removed - changed the dumb for(;;) putchar into an fwrite call - cure multiple memory leaks in virsh - fixed const-correctness of the callback function - use a wrapper around strtoll - replaced some !strcmp with STREQ (etc) - use AC_SYS_LARGEFILE to get portable support for 64-bit file offsets 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: configure.in =================================================================== RCS file: /data/cvs/libvirt/configure.in,v retrieving revision 1.90 diff -u -p -r1.90 configure.in --- configure.in 30 Sep 2007 21:09:29 -0000 1.90 +++ configure.in 16 Oct 2007 18:37:27 -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([regexec]) 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 18:37:28 -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 18:37:28 -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 18:37:29 -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 18:37:31 -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 18:37:31 -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 18:37:33 -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 18:37:34 -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 18:37:37 -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,77 @@ 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 = 0; + int found, ret = FALSE; + + if (!vshConnectionUsability (ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain (ctl, cmd, "domain", &name))) + goto done; + + if (!(path = vshCommandOptString (cmd, "path", NULL))) + goto done; + + offset = vshCommandOptInt64 (cmd, "offset", &found); + if (!found) goto done; + + size = vshCommandOptInt (cmd, "size", &found); + if (!found) goto done; + + buffer = malloc (size); + if (!buffer) { + vshError (ctl, FALSE, _("Memory allocation failed for buffer")); + goto done; + } + + if (virDomainBlockPeek (dom, path, offset, size, buffer) == -1) { + vshError (ctl, FALSE, _("Failed to peek block device %s %s"), + name, path); + goto done; + } + + /* Dump out the memory - user can pipe into od/hexdump if they + * desire. + */ + if (size > 0) { + if (fwrite (buffer, size, 1, stdout) != 1) { + vshError (ctl, FALSE, "write: %s", strerror (errno)); + goto done; + } + } + + ret = TRUE; + done: + if (buffer) free (buffer); + if (dom) virDomainFree(dom); + return ret; +} + /* * "suspend" command */ @@ -3702,6 +3774,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}, @@ -3952,6 +4025,37 @@ vshCommandOptInt(vshCmd * cmd, const cha return res; } +static int +xstrtoint64 (char const *s, int base, long long *result) +{ + char *p; + + errno = 0; + *result = strtoll (s, &p, base); + if (errno || !(*p == 0 || *p == '\n') || p == s) + return -1; + return 0; +} + +/* + * 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; + + if (arg && arg->data) { + if (xstrtoint64 (arg->data, 10, &res) == 0) { + *found = TRUE; + return res; + } + } + *found = FALSE; + return -1; +} + /* * Returns option as STRING */ 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 18:37:37 -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 18:37:40 -0000 @@ -18,6 +18,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 +41,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 +1337,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, + 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; + const char *dst; + const char *mode; + + /* 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; + } + + 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 (STREQ (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 (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, + 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, + const char *drvName, const 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) && (STREQ (mode, "r"))) + virBufferVSprintf(buf, " <readonly/>\n"); + else if ((mode != NULL) && (STREQ (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 +1680,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 +3802,125 @@ 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, + 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, + 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. */ + /* 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.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 18:37:40 -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 18:37:42 -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 18:37:42 -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 18:37:42 -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 18:37:42 -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
-- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list