return ret;
}
+/* Use the snapshot_blkdev command to convert the existing file for
+ * device into a read-only backing file of a new qcow2 image located
+ * at file. */
+int
+qemuMonitorDiskSnapshot(qemuMonitorPtr mon, const char *device,
+ const char *file)
+{
+ int ret;
+
+ VIR_DEBUG("mon=%p, device=%s, file=%s", mon, device, file);
+
+ if (!mon) {
+ qemuReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("monitor must not be NULL"));
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONDiskSnapshot(mon, device, file);
+ else
+ ret = qemuMonitorTextDiskSnapshot(mon, device, file);
+ return ret;
+}
+
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
char **reply,
int qemuMonitorLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+int qemuMonitorDiskSnapshot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file);
+
int qemuMonitorArbitraryCommand(qemuMonitorPtr mon,
const char *cmd,
char **reply,
return ret;
}
+int
+qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon, const char *device,
+ const char *file)
+{
+ int ret;
+ virJSONValuePtr cmd;
+ virJSONValuePtr reply = NULL;
+
+ cmd = qemuMonitorJSONMakeCommand("snapshot-blkdev-sync",
+ "s:device", device,
+ "s:snapshot-file", file,
+ NULL);
+ if (!cmd)
+ return -1;
+
+ if ((ret = qemuMonitorJSONCommand(mon, cmd, &reply)) < 0)
+ goto cleanup;
+
+ if (qemuMonitorJSONHasError(reply, "CommandNotFound") &&
+ qemuMonitorCheckHMP(mon, "snapshot_blkdev")) {
+ VIR_DEBUG("snapshot-blkdev-sync command not found, trying HMP");
+ ret = qemuMonitorTextDiskSnapshot(mon, device, file);
+ goto cleanup;
+ }
+
+ ret = qemuMonitorJSONCheckError(cmd, reply);
+
+cleanup:
+ virJSONValueFree(cmd);
+ virJSONValueFree(reply);
+ return ret;
+}
+
int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
const char *cmd_str,
char **reply_str,
int qemuMonitorJSONLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorJSONDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+int qemuMonitorJSONDiskSnapshot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file);
+
int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon,
const char *cmd_str,
char **reply_str,
return ret;
}
+int
+qemuMonitorTextDiskSnapshot(qemuMonitorPtr mon, const char *device,
+ const char *file)
+{
+ char *cmd = NULL;
+ char *reply = NULL;
+ int ret = -1;
+ char *safename;
+
+ if (!(safename = qemuMonitorEscapeArg(file)) ||
+ virAsprintf(&cmd, "snapshot_blkdev %s \"%s\"", device, safename) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (qemuMonitorHMPCommand(mon, cmd, &reply)) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("failed to take snapshot using command '%s'"), cmd);
+ goto cleanup;
+ }
+
+ if (strstr(reply, "error while creating qcow2") != NULL) {
+ qemuReportError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to take snapshot: %s"), reply);
+ goto cleanup;
+ }
+
+ /* XXX Should we scrape 'info block' output for
+ * 'device:... file=name backing_file=oldname' to make sure the
+ * command succeeded? */
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(safename);
+ VIR_FREE(cmd);
+ VIR_FREE(reply);
+ return ret;
+}
+
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply)
{
int qemuMonitorTextLoadSnapshot(qemuMonitorPtr mon, const char *name);
int qemuMonitorTextDeleteSnapshot(qemuMonitorPtr mon, const char *name);
+int qemuMonitorTextDiskSnapshot(qemuMonitorPtr mon,
+ const char *device,
+ const char *file);
+
int qemuMonitorTextArbitraryCommand(qemuMonitorPtr mon, const char *cmd,
char **reply);