]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Add APIs for issuing 'eject' and 'change dev' monitor commands
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 23 Sep 2009 11:51:59 +0000 (12:51 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Tue, 29 Sep 2009 10:54:21 +0000 (11:54 +0100)
* 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
src/qemu/qemu_monitor_text.c
src/qemu/qemu_monitor_text.h

index a625583a7a9c2e4fc685649406e53342c3d05031..ce06f658e35b7c22a87c257627c75a360146a85b 100644 (file)
@@ -4572,9 +4572,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;
@@ -4620,53 +4620,19 @@ 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;
+    return ret;
 }
 
 static int
index 2bca58fae74975e00894c456848290f20cef14ec..43bca4c11ac5759747ca69e9d9d50f422c88cba1 100644 (file)
 
 #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;
+}
+
index 6328fbbba71fefcf474e333f4a5bffa82bc5c069..cd9354a19b1128cf01eb2e2911dd5f8b1370e6d6 100644 (file)
@@ -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 */