Signed-off-by: Jim Paris <jim(a)jtan.com>
---
src/qemu_driver.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 109 insertions(+), 4 deletions(-)
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index f2c4316..b0b6d62 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -2041,10 +2041,115 @@ static int qemudDomainSave(virDomainPtr dom,
static int qemudDomainRestore(virConnectPtr conn,
- const char *path ATTRIBUTE_UNUSED) {
- /*struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;*/
- qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED, "restore is not
supported");
- return -1;
+ const char *path) {
+ struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
+ struct qemud_vm_def *def;
+ struct qemud_vm *vm;
+ int fd;
+ char *xml;
+ struct qemud_save_header header;
+
+ /* Verify the header and read the XML */
+ if ((fd = open(path, O_RDONLY)) < 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "cannot read domain image");
+ return -1;
+ }
+
+ if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "failed to read qemu header");
+ close(fd);
+ return -1;
+ }
+
+ if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "image magic is incorrect");
+ close(fd);
+ return -1;
+ }
+
+ if (header.version > QEMUD_SAVE_VERSION) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "image version is not supported (%d > %d)",
+ header.version, QEMUD_SAVE_VERSION);
+ close(fd);
+ return -1;
+ }
+
+ if ((xml = (char *)malloc(header.xml_len)) == NULL) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "out of memory");
+ close(fd);
+ return -1;
+ }
+
+ if (saferead(fd, xml, header.xml_len) != header.xml_len) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "failed to read XML");
+ close(fd);
+ free(xml);
+ return -1;
+ }
+
+ /* Create a domain from this XML */
+ if (!(def = qemudParseVMDef(conn, driver, xml, NULL))) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "failed to parse XML");
+ close(fd);
+ free(xml);
+ return -1;
+ }
+ free(xml);
+
+ /* Ensure the name and UUID don't already exist in an active VM */
+ vm = qemudFindVMByUUID(driver, def->uuid);
+ if (!vm) vm = qemudFindVMByName(driver, def->name);
+ if (vm && qemudIsActiveVM(vm)) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "domain is already active as '%s'",
vm->def->name);
+ close(fd);
+ return -1;
+ }
+
+ if (!(vm = qemudAssignVMDef(conn, driver, def))) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "failed to assign new VM");
+ qemudFreeVMDef(def);
+ close(fd);
+ return -1;
+ }
+
+ /* Set the migration source and start it up. */
+ snprintf(vm->migrateFrom, sizeof(vm->migrateFrom), "stdio");
+ vm->stdin = fd;
+
+ if (qemudStartVMDaemon(conn, driver, vm) < 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "failed to start VM");
+ if (!vm->configFile[0])
+ qemudRemoveInactiveVM(driver, vm);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ vm->migrateFrom[0] = '\0';
+ vm->stdin = -1;
+
+ /* If it was running before, resume it now. */
+ if (header.was_running) {
+ char *info;
+ if (qemudMonitorCommand(driver, vm, "cont\r", &info) < 0) {
+ qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ "failed to resume domain");
+ return -1;
+ }
+ free(info);
+ vm->state = VIR_DOMAIN_RUNNING;
+ }
+
+ return 0;
}
--
1.5.3.rc4