[Libvir] PATCH: Autodetect QEMU version

Daniel P. Berrange berrange at redhat.com
Wed Feb 21 15:45:35 UTC 2007


When I tested out the libvirt 0.2.0 in Fedora rawhide I discovered that the
syntax for specifying VNC display numbers changes in QEMU 0.9.0. Previously
you would use

    -vnc  7

Now you need to use

    -vnc :7

For current Fedora RPM I just hacked in a workaround to always add ':', but
we need to be able to detect the version properly. So I'm attaching a patch
which spawns '/usr/bin/qemu' and groks its command line help to extract the
version number. It then uses appropriate VNC argument syntax based on the
version. At the same time I also check for whether -no-kqemu is available
so we can turn off KQEMU support if it is not available.

Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
-------------- next part --------------
Index: qemud/conf.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/conf.c,v
retrieving revision 1.27
diff -u -p -r1.27 conf.c
--- qemud/conf.c	20 Feb 2007 19:09:44 -0000	1.27
+++ qemud/conf.c	21 Feb 2007 15:40:41 -0000
@@ -231,8 +231,8 @@ static const char *qemudDefaultBinaryFor
 }
 
 /* Find the fully qualified path to the binary for an architecture */
-static char *qemudLocateBinaryForArch(struct qemud_server *server,
-                                      int virtType, const char *arch) {
+char *qemudLocateBinaryForArch(struct qemud_server *server,
+                               int virtType, const char *arch) {
     const char *name;
     char *path;
 
@@ -551,7 +551,7 @@ static struct qemud_vm_def *qemudParseXM
 
     if (!strcmp((char *)prop, "qemu"))
         def->virtType = QEMUD_VIRT_QEMU;
-    else if (!strcmp((char *)prop, "kqemu"))
+    else if (!strcmp((char *)prop, "kqemu") && server->qemuHasKQEMU)
         def->virtType = QEMUD_VIRT_KQEMU;
     else if (!strcmp((char *)prop, "kvm"))
         def->virtType = QEMUD_VIRT_KVM;
@@ -949,7 +949,7 @@ int qemudBuildCommandLine(struct qemud_s
 
     len = 1 + /* qemu */
         2 + /* machine type */
-        (vm->def->virtType == QEMUD_VIRT_QEMU ? 1 : 0) + /* Disable kqemu */
+        (server->qemuHasKQEMU && vm->def->virtType == QEMUD_VIRT_QEMU ? 1 : 0) + /* Disable kqemu */
         2 * vm->def->ndisks + /* disks*/
         (vm->def->nnets > 0 ? (4 * vm->def->nnets) : 2) + /* networks */
         2 + /* memory*/
@@ -974,9 +974,9 @@ int qemudBuildCommandLine(struct qemud_s
         goto no_memory;
     if (!((*argv)[++n] = strdup(vm->def->os.machine)))
         goto no_memory;
-    if (vm->def->virtType == QEMUD_VIRT_QEMU) {
+    if (server->qemuHasKQEMU && vm->def->virtType == QEMUD_VIRT_QEMU) {
         if (!((*argv)[++n] = strdup("-no-kqemu")))
-        goto no_memory;
+            goto no_memory;
     }
     if (!((*argv)[++n] = strdup("-m")))
         goto no_memory;
@@ -993,8 +993,8 @@ int qemudBuildCommandLine(struct qemud_s
         goto no_memory;
 
     if (!(vm->def->features & QEMUD_FEATURE_ACPI)) {
-    if (!((*argv)[++n] = strdup("-no-acpi")))
-        goto no_memory;
+        if (!((*argv)[++n] = strdup("-no-acpi")))
+            goto no_memory;
     }
 
     for (i = 0 ; i < vm->def->os.nBootDevs ; i++) {
@@ -1100,7 +1100,14 @@ int qemudBuildCommandLine(struct qemud_s
 
     if (vm->def->graphicsType == QEMUD_GRAPHICS_VNC) {
         char port[10];
-        snprintf(port, 10, "%d", vm->def->vncActivePort - 5900);
+        int ret;
+        ret = snprintf(port, sizeof(port),
+                       (server->qemuVersion >= 9000 ?
+                        ":%d" : "%d"),
+                       vm->def->vncActivePort - 5900);
+        if (ret < 0 || ret >= (int)sizeof(port))
+            goto error;
+
         if (!((*argv)[++n] = strdup("-vnc")))
             goto no_memory;
         if (!((*argv)[++n] = strdup(port)))
Index: qemud/conf.h
===================================================================
RCS file: /data/cvs/libvirt/qemud/conf.h,v
retrieving revision 1.7
diff -u -p -r1.7 conf.h
--- qemud/conf.h	15 Feb 2007 19:04:45 -0000	1.7
+++ qemud/conf.h	21 Feb 2007 15:40:41 -0000
@@ -26,6 +26,8 @@
 
 #include "internal.h"
 
+char *qemudLocateBinaryForArch(struct qemud_server *server,
+                               int virtType, const char *arch);
 int qemudBuildCommandLine(struct qemud_server *server,
                           struct qemud_vm *vm,
                           char ***argv);
Index: qemud/driver.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/driver.c,v
retrieving revision 1.10
diff -u -p -r1.10 driver.c
--- qemud/driver.c	16 Feb 2007 18:30:55 -0000	1.10
+++ qemud/driver.c	21 Feb 2007 15:40:41 -0000
@@ -34,6 +34,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
+#include <sys/wait.h>
 
 #include <libvirt/virterror.h>
 
@@ -54,6 +55,75 @@ void qemudReportError(struct qemud_serve
     }
 }
 
+int qemudExtractVersion(const char *qemu, int *version, int *hasKQEMU) {
+    int child;
+    int newstdout[2];
+
+    if (pipe(newstdout) < 0) {
+        return -1;
+    }
+
+    if ((child = fork()) < 0) {
+        return -1;
+    }
+
+    if (child == 0) { /* Kid */
+        if (close(STDIN_FILENO) < 0)
+            goto cleanup1;
+        if (close(STDERR_FILENO) < 0)
+            goto cleanup1;
+        if (close(newstdout[0]) < 0)
+            goto cleanup1;
+        if (dup2(newstdout[1], STDOUT_FILENO) < 0)
+            goto cleanup1;
+
+        /* Just in case QEMU is translated someday.. */
+        setenv("LANG", "C", 1);
+        execl(qemu, qemu, (char*)NULL);
+
+    cleanup1:
+        _exit(-1); /* Just in case */
+    } else { /* Parent */
+        char help[4096]; /* Ought to be enough to hold QEMU help screen */
+        int got, ret = -1;
+        int major, minor, micro;
+
+        if (close(newstdout[1]) < 0)
+            goto cleanup2;
+
+        if ((got = read(newstdout[0], help, sizeof(help)-1)) < 0)
+            goto cleanup2;
+        help[got] = '\0';
+
+        if (sscanf(help, "QEMU PC emulator version %d.%d.%d", &major,&minor, &micro) != 3) {
+            goto cleanup2;
+        }
+
+        if (strstr(help, "-no-kqemu"))
+            *hasKQEMU = 1;
+        else
+            *hasKQEMU = 0;
+        *version = (major * 1000 * 1000) + (minor * 1000) + micro;
+        ret = 0;
+
+        qemudDebug("Version %d %d %d  Cooked version: %d, with KQEMU ? %d",
+                   major, minor, micro, *version, *hasKQEMU);
+
+    cleanup2:
+        if (close(newstdout[0]) < 0)
+            ret = -1;
+
+        if (waitpid(child, &got, 0) != child ||
+            WEXITSTATUS(got) != 1) {
+            qemudLog(QEMUD_ERR, "Unexpected exit status from qemu %d pid %d", got, child);
+            ret = -1;
+        }
+
+        return ret;
+    }
+}
+
+
 int qemudMonitorCommand(struct qemud_server *server ATTRIBUTE_UNUSED,
                         struct qemud_vm *vm,
                         const char *cmd,
Index: qemud/driver.h
===================================================================
RCS file: /data/cvs/libvirt/qemud/driver.h,v
retrieving revision 1.3
diff -u -p -r1.3 driver.h
--- qemud/driver.h	14 Feb 2007 16:20:38 -0000	1.3
+++ qemud/driver.h	21 Feb 2007 15:40:41 -0000
@@ -30,6 +30,7 @@
 void qemudReportError(struct qemud_server *server,
                       int code, const char *fmt, ...);
 
+int qemudExtractVersion(const char *qemu, int *version, int *hasKQEMU);
 int qemudGetCPUInfo(unsigned int *cpus, unsigned int *mhz,
                     unsigned int *nodes, unsigned int *sockets,
                     unsigned int *cores, unsigned int *threads);
Index: qemud/internal.h
===================================================================
RCS file: /data/cvs/libvirt/qemud/internal.h,v
retrieving revision 1.12
diff -u -p -r1.12 internal.h
--- qemud/internal.h	16 Feb 2007 18:30:55 -0000	1.12
+++ qemud/internal.h	21 Feb 2007 15:40:41 -0000
@@ -275,6 +275,7 @@ struct qemud_server {
     int nsockets;
     struct qemud_socket *sockets;
     int qemuVersion;
+    int qemuHasKQEMU;
     int nclients;
     struct qemud_client *clients;
     int sigread;
Index: qemud/qemud.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/qemud.c,v
retrieving revision 1.23
diff -u -p -r1.23 qemud.c
--- qemud/qemud.c	20 Feb 2007 17:51:41 -0000	1.23
+++ qemud/qemud.c	21 Feb 2007 15:40:42 -0000
@@ -411,20 +411,26 @@ static struct qemud_server *qemudInitial
     struct qemud_server *server;
     char sockname[PATH_MAX];
     char roSockname[PATH_MAX];
+    char *binary = NULL;
 
     if (!(server = calloc(1, sizeof(struct qemud_server)))) {
         qemudLog(QEMUD_ERR, "Failed to allocate struct qemud_server");
         return NULL;
     }
 
-    /* XXX extract actual version */
-    server->qemuVersion = (0*1000000)+(8*1000)+(0);
     /* We don't have a dom-0, so start from 1 */
     server->nextvmid = 1;
     server->sigread = sigread;
 
     roSockname[0] = '\0';
 
+    if (!(binary = qemudLocateBinaryForArch(server, QEMUD_VIRT_QEMU, "i686")))
+        goto cleanup;
+    if (qemudExtractVersion(binary, &server->qemuVersion, &server->qemuHasKQEMU) < 0)
+        goto cleanup;
+    free(binary);
+    binary = NULL;
+
     if (qemudInitPaths(sys, server->configDir, server->networkConfigDir,
                        sockname, roSockname, PATH_MAX) < 0)
         goto cleanup;
@@ -451,6 +457,8 @@ static struct qemud_server *qemudInitial
 
         free(server);
     }
+    if (binary)
+        free(binary);
     return NULL;
 }
 


More information about the libvir-list mailing list