* src/qemu/qemu_driver.c (qemuDomainSaveImageGetXMLDesc) (qemuDomainSaveImageDefineXML): New functions. (qemuDomainSaveImageOpen): Add parameter. (qemuDomainRestoreFlags, qemuDomainObjRestore): Adjust clients. (qemuDomainSaveInternal): Simplify array expansion. --- Tested via: virsh save dom dom.save virsh save-image-dumpxml dom.save > dom.xml edit dom.xml virsh save-image-define dom.save dom.xml virsh save-image-edit dom.save virsh restore dom.save and the edits in dom.xml showed up in my editor, as well as on the restore. src/qemu/qemu_driver.c | 111 +++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 100 insertions(+), 11 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index d1fa06f..148770f 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -2214,14 +2214,14 @@ qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom, unsigned long long pad = QEMU_MONITOR_MIGRATE_TO_FILE_BS - (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS); + size_t len = header.xml_len; - if (VIR_REALLOC_N(xml, header.xml_len + pad) < 0) { + if (VIR_EXPAND_N(xml, len, pad) < 0) { virReportOOMError(); goto endjob; } - memset(xml + header.xml_len, 0, pad); offset += pad; - header.xml_len += pad; + header.xml_len = len; } /* Obtain the file handle. */ @@ -3623,29 +3623,30 @@ cleanup: return ret; } -static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(6) +static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4) qemuDomainSaveImageOpen(struct qemud_driver *driver, const char *path, virDomainDefPtr *ret_def, struct qemud_save_header *ret_header, bool bypass_cache, virFileDirectFdPtr *directFd, - const char *xmlin) + const char *xmlin, bool edit) { int fd; struct qemud_save_header header; char *xml = NULL; virDomainDefPtr def = NULL; - int directFlag = 0; + int oflags = edit ? O_RDWR : O_RDONLY; if (bypass_cache) { - directFlag = virFileDirectFdFlag(); + int directFlag = virFileDirectFdFlag(); if (directFlag < 0) { qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", _("bypass cache unsupported by this system")); goto error; } + oflags |= directFlag; } - if ((fd = virFileOpenAs(path, O_RDONLY | directFlag, 0, + if ((fd = virFileOpenAs(path, oflags, 0, getuid(), getgid(), 0)) < 0) { if ((fd != -EACCES && fd != -EPERM) || driver->user == getuid()) { @@ -3656,7 +3657,7 @@ qemuDomainSaveImageOpen(struct qemud_driver *driver, /* Opening as root failed, but qemu runs as a different user * that might have better luck. */ - if ((fd = virFileOpenAs(path, O_RDONLY | directFlag, 0, + if ((fd = virFileOpenAs(path, oflags, 0, driver->user, driver->group, VIR_FILE_OPEN_AS_UID)) < 0) { qemuReportError(VIR_ERR_OPERATION_FAILED, @@ -3866,7 +3867,7 @@ qemuDomainRestoreFlags(virConnectPtr conn, fd = qemuDomainSaveImageOpen(driver, path, &def, &header, (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0, - &directFd, dxml); + &directFd, dxml, false); if (fd < 0) goto cleanup; @@ -3912,6 +3913,92 @@ qemuDomainRestore(virConnectPtr conn, return qemuDomainRestoreFlags(conn, path, NULL, 0); } +static char * +qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path, + unsigned int flags) +{ + struct qemud_driver *driver = conn->privateData; + char *ret = NULL; + virDomainDefPtr def = NULL; + int fd = -1; + struct qemud_save_header header; + + /* We only take subset of virDomainDefFormat flags. */ + virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL); + + qemuDriverLock(driver); + + fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL, + NULL, false); + + if (fd < 0) + goto cleanup; + + ret = qemuDomainDefFormatXML(driver, def, flags); + +cleanup: + virDomainDefFree(def); + VIR_FORCE_CLOSE(fd); + qemuDriverUnlock(driver); + return ret; +} + +static int +qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path, + const char *dxml, unsigned int flags) +{ + struct qemud_driver *driver = conn->privateData; + int ret = -1; + virDomainDefPtr def = NULL; + int fd = -1; + struct qemud_save_header header; + char *xml = NULL; + size_t len; + + virCheckFlags(0, -1); + + qemuDriverLock(driver); + + fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL, + dxml, true); + + if (fd < 0) + goto cleanup; + + xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_SECURE); + if (!xml) + goto cleanup; + len = strlen(xml) + 1; + + if (len > header.xml_len) { + qemuReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("new xml too large to fit in file")); + } + if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (lseek(fd, sizeof(header), SEEK_SET) != sizeof(header)) { + virReportSystemError(errno, _("cannot seek in '%s'"), path); + goto cleanup; + } + if (safewrite(fd, xml, len) != len || + VIR_CLOSE(fd) < 0) { + virReportSystemError(errno, _("failed to write xml to '%s'"), path); + goto cleanup; + } + + ret = 0; + +cleanup: + virDomainDefFree(def); + VIR_FORCE_CLOSE(fd); + VIR_FREE(xml); + qemuDriverUnlock(driver); + return ret; +} + static int qemuDomainObjRestore(virConnectPtr conn, struct qemud_driver *driver, @@ -3926,7 +4013,7 @@ qemuDomainObjRestore(virConnectPtr conn, virFileDirectFdPtr directFd = NULL; fd = qemuDomainSaveImageOpen(driver, path, &def, &header, - bypass_cache, &directFd, NULL); + bypass_cache, &directFd, NULL, false); if (fd < 0) goto cleanup; @@ -8690,6 +8777,8 @@ static virDriver qemuDriver = { .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */ .domainRestore = qemuDomainRestore, /* 0.2.0 */ .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */ + .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */ + .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */ .domainCoreDump = qemudDomainCoreDump, /* 0.7.0 */ .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */ .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */ -- 1.7.4.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list