* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add new APis
qemuMonitorChangeMedia and qemuMonitorEjectMedia. Pull in code
for qemudEscape
* src/qemu/qemu_driver.c: Remove code that directly issues 'eject'
and 'change' commands in favour of API calls.
---
src/qemu/qemu_driver.c | 52 +++-----------
src/qemu/qemu_monitor_text.c | 159 ++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_monitor_text.h | 10 +++
3 files changed, 178 insertions(+), 43 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a0b5e49..b15dc03 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4573,9 +4573,9 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn,
unsigned int qemuCmdFlags)
{
virDomainDiskDefPtr origdisk = NULL, newdisk;
- char *cmd, *reply, *safe_path;
char *devname = NULL;
int i;
+ int ret;
origdisk = NULL;
newdisk = dev->data.disk;
@@ -4621,52 +4621,18 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn,
}
if (newdisk->src) {
- safe_path = qemudEscapeMonitorArg(newdisk->src);
- if (!safe_path) {
- virReportOOMError(conn);
- VIR_FREE(devname);
- return -1;
- }
- if (virAsprintf(&cmd, "change %s \"%s\"", devname,
safe_path) == -1) {
- virReportOOMError(conn);
- VIR_FREE(safe_path);
- VIR_FREE(devname);
- return -1;
- }
- VIR_FREE(safe_path);
-
- } else if (virAsprintf(&cmd, "eject %s", devname) == -1) {
- virReportOOMError(conn);
- VIR_FREE(devname);
- return -1;
- }
- VIR_FREE(devname);
-
- if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
- qemudReportError(conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
- "%s", _("could not change cdrom media"));
- VIR_FREE(cmd);
- return -1;
+ ret = qemuMonitorChangeMedia(vm, devname, newdisk->src);
+ } else {
+ ret = qemuMonitorEjectMedia(vm, devname);
}
- /* If the command failed qemu prints:
- * device not found, device is locked ...
- * No message is printed on success it seems */
- DEBUG ("%s: ejectable media change reply: %s", vm->def->name,
reply);
- if (strstr(reply, "\ndevice ")) {
- qemudReportError (conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
- _("changing cdrom media failed: %s"), reply);
- VIR_FREE(reply);
- VIR_FREE(cmd);
- return -1;
+ if (ret == 0) {
+ VIR_FREE(origdisk->src);
+ origdisk->src = newdisk->src;
+ newdisk->src = NULL;
+ origdisk->type = newdisk->type;
}
- VIR_FREE(reply);
- VIR_FREE(cmd);
- VIR_FREE(origdisk->src);
- origdisk->src = newdisk->src;
- newdisk->src = NULL;
- origdisk->type = newdisk->type;
return 0;
}
diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c
index be13dce..8be8047 100644
--- a/src/qemu/qemu_monitor_text.c
+++ b/src/qemu/qemu_monitor_text.c
@@ -40,6 +40,84 @@
#define VIR_FROM_THIS VIR_FROM_QEMU
+static char *qemudEscape(const char *in, int shell)
+{
+ int len = 0;
+ int i, j;
+ char *out;
+
+ /* To pass through the QEMU monitor, we need to use escape
+ sequences: \r, \n, \", \\
+
+ To pass through both QEMU + the shell, we need to escape
+ the single character ' as the five characters '\\''
+ */
+
+ for (i = 0; in[i] != '\0'; i++) {
+ switch(in[i]) {
+ case '\r':
+ case '\n':
+ case '"':
+ case '\\':
+ len += 2;
+ break;
+ case '\'':
+ if (shell)
+ len += 5;
+ else
+ len += 1;
+ break;
+ default:
+ len += 1;
+ break;
+ }
+ }
+
+ if (VIR_ALLOC_N(out, len + 1) < 0)
+ return NULL;
+
+ for (i = j = 0; in[i] != '\0'; i++) {
+ switch(in[i]) {
+ case '\r':
+ out[j++] = '\\';
+ out[j++] = 'r';
+ break;
+ case '\n':
+ out[j++] = '\\';
+ out[j++] = 'n';
+ break;
+ case '"':
+ case '\\':
+ out[j++] = '\\';
+ out[j++] = in[i];
+ break;
+ case '\'':
+ if (shell) {
+ out[j++] = '\'';
+ out[j++] = '\\';
+ out[j++] = '\\';
+ out[j++] = '\'';
+ out[j++] = '\'';
+ } else {
+ out[j++] = in[i];
+ }
+ break;
+ default:
+ out[j++] = in[i];
+ break;
+ }
+ }
+ out[j] = '\0';
+
+ return out;
+}
+
+static char *qemudEscapeMonitorArg(const char *in)
+{
+ return qemudEscape(in, 0);
+}
+
+
/* Throw away any data available on the monitor
* This is done before executing a command, in order
* to allow re-synchronization if something went badly
@@ -651,3 +729,84 @@ int qemuMonitorSetBalloon(const virDomainObjPtr vm,
return ret;
}
+int qemuMonitorEjectMedia(const virDomainObjPtr vm,
+ const char *devname)
+{
+ char *cmd = NULL;
+ char *reply = NULL;
+ int ret = -1;
+
+ if (virAsprintf(&cmd, "eject %s", devname) < 0) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("could not eject media on %s"), devname);
+ goto cleanup;
+ }
+
+ /* If the command failed qemu prints:
+ * device not found, device is locked ...
+ * No message is printed on success it seems */
+ DEBUG ("%s: ejectable media change reply: %s", vm->def->name,
reply);
+ if (strstr(reply, "\ndevice ")) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("could not eject media on %s: %s"), devname,
reply);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(reply);
+ VIR_FREE(cmd);
+ return ret;
+}
+
+
+int qemuMonitorChangeMedia(const virDomainObjPtr vm,
+ const char *devname,
+ const char *newmedia)
+{
+ char *cmd = NULL;
+ char *reply = NULL;
+ char *safepath = NULL;
+ int ret = -1;
+
+ if (!(safepath = qemudEscapeMonitorArg(newmedia))) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (virAsprintf(&cmd, "change %s \"%s\"", devname, safepath)
< 0) {
+ virReportOOMError(NULL);
+ goto cleanup;
+ }
+
+ if (qemudMonitorCommand(vm, cmd, &reply) < 0) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("could not eject media on %s"), devname);
+ goto cleanup;
+ }
+
+ /* If the command failed qemu prints:
+ * device not found, device is locked ...
+ * No message is printed on success it seems */
+ DEBUG ("%s: ejectable media change reply: %s", vm->def->name,
reply);
+ if (strstr(reply, "\ndevice ")) {
+ qemudReportError(NULL, NULL, NULL, VIR_ERR_OPERATION_FAILED,
+ _("could not eject media on %s: %s"), devname,
reply);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(reply);
+ VIR_FREE(cmd);
+ VIR_FREE(safepath);
+ return ret;
+}
+
diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h
index e115791..d05dea1 100644
--- a/src/qemu/qemu_monitor_text.h
+++ b/src/qemu/qemu_monitor_text.h
@@ -81,4 +81,14 @@ int qemuMonitorSetVNCPassword(const virDomainObjPtr vm,
int qemuMonitorSetBalloon(const virDomainObjPtr vm,
unsigned long newmem);
+/* XXX should we pass the virDomainDiskDefPtr instead
+ * and hide devname details inside monitor. Reconsider
+ * this when doing the QMP implementation
+ */
+int qemuMonitorEjectMedia(const virDomainObjPtr vm,
+ const char *devname);
+int qemuMonitorChangeMedia(const virDomainObjPtr vm,
+ const char *devname,
+ const char *newmedia);
+
#endif /* QEMU_MONITOR_TEXT_H */
--
1.6.2.5