[libvirt] [PATCH 09/27] Add APIs for issuing 'eject' and 'change dev' monitor commands

Daniel P. Berrange berrange at redhat.com
Thu Sep 24 15:00:11 UTC 2009


* 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




More information about the libvir-list mailing list