Reading from the qemu monitor pulls in a whole bunch of
useless control characters. For example, sending the
command 'somecomm' to the monitor returns:

somecomm
unknown command: 'somecomm'
(qemu)

Which is 36 characters, however we end up reading over 200.
The amount we read actually grows quadratically as a function
of the command length. This prevents us from reporting monitor
output to the user (incase some command fails) and seriously
diminishes the value of the domain logfiles.

The attached patch tries to sanitize this a bit. After reading
all the output, we search for the first occurrence of the full
command string. If found, we search from there for the first
newline (which marks the beginning of the monitor response).
If these are found, we only return the command, and everything
after the newline. If only the command is found, we just drop
everything before it.

I've tested this on f9 and f8, there didn't seem to be any
problems. I think this should be pretty future proof as
well, so we hopefully won't be throwing out anything
valuable.

Thanks,
Cole

diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index 9d8f75a..87c9be7 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -1670,7 +1670,7 @@ qemudMonitorCommand (const struct qemud_driver *driver ATTRIBUTE_UNUSED,
                      const char *cmd,
                      char **reply) {
     int size = 0;
-    char *buf = NULL;
+    char *buf = NULL, *tmpbuf = NULL, *nlptr = NULL, *commptr = NULL;
     size_t cmdlen = strlen(cmd);
 
     if (safewrite(vm->monitor, cmd, cmdlen) != cmdlen)
@@ -1708,7 +1708,31 @@ qemudMonitorCommand (const struct qemud_driver *driver ATTRIBUTE_UNUSED,
 
         /* Look for QEMU prompt to indicate completion */
         if (buf && ((tmp = strstr(buf, "\n(qemu) ")) != NULL)) {
-            tmp[0] = '\0';
+            /* Preserve the newline */
+            tmp[1] = '\0';
+
+            /* The monitor doesn't dump clean output after we have written to
+             * it. Every character we write dumps a bunch of useless stuff,
+             * so the result looks like "cXcoXcomXcommXcommaXcommanXcommand"
+             * Try to throw away everything before the first full command
+             * occurence, and inbetween the command and the newline starting
+             * the response
+             */
+            if ((commptr = strstr(buf, cmd))) {
+                tmpbuf = buf;
+                buf = NULL;
+                if ((nlptr = strchr(commptr, '\n'))) {
+                    if (VIR_ALLOC_N(buf, strlen(cmd) + strlen(nlptr) + 1) < 0)
+                        goto error;
+                    strncpy(buf, cmd, strlen(cmd));
+                    strcat(buf, nlptr);
+                } else {
+                    if ((buf = strdup(commptr)) == NULL)
+                        goto error;
+                }
+                VIR_FREE(tmpbuf);
+            }
+
             break;
         }
     pollagain:
@@ -3103,7 +3127,7 @@ static int qemudDomainChangeEjectableMedia(virDomainPtr dom,
 
     if (qemudMonitorCommand(driver, vm, cmd, &reply) < 0) {
         qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
-                         "%s", _("cannot change cdrom media"));
+                         "%s", _("could not change cdrom media"));
         VIR_FREE(cmd);
         return -1;
     }
@@ -3114,7 +3138,7 @@ static int qemudDomainChangeEjectableMedia(virDomainPtr dom,
     DEBUG ("ejectable media change reply: %s", reply);
     if (strstr(reply, "\ndevice ")) {
         qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
-                          "%s", _("changing cdrom media failed"));
+                          _("changing cdrom media failed: %s"), reply);
         VIR_FREE(reply);
         VIR_FREE(cmd);
         return -1;
--
Libvir-list mailing list
Libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to