From 73048102c096c92d531ffddf51d178d02a7f755a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 23 Feb 2007 17:15:18 +0000 Subject: [PATCH] Autodetect QEMU version and adjust command line arg accordingly --- ChangeLog | 7 +++ qemud/conf.c | 131 ++++++++++++++++++++++++++++++++++++++++++++--- qemud/conf.h | 1 + qemud/driver.c | 3 ++ qemud/internal.h | 8 +++ qemud/qemud.c | 2 - 6 files changed, 144 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 314c155ec3..2e4ab0dd77 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Fri Feb 23 12:14:34 EST 2007 Daniel P. Berrange + + * qemud/driver.c, qemud/internal.h, qemud/qemud.c, qemud/conf.c, + qemud/conf.h: Added code to detect QEMU version number. Adapt + command line construction code to use correct options for VNC + and KQEMU based on version number + Fri Feb 23 10:52:23 EST 2007 Daniel P. Berrange * qemud/Makefile.am: Fix up name of init script in EXTRA_DIST diff --git a/qemud/conf.c b/qemud/conf.c index 68d32ba814..54d67f430d 100644 --- a/qemud/conf.c +++ b/qemud/conf.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -257,6 +258,112 @@ static char *qemudLocateBinaryForArch(struct qemud_server *server, return path; } + +static int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) { + pid_t child; + int newstdout[2]; + + *flags = 0; + *version = 0; + + if (pipe(newstdout) < 0) { + return -1; + } + + if ((child = fork()) < 0) { + close(newstdout[0]); + close(newstdout[1]); + 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; + + reread: + if ((got = read(newstdout[0], help, sizeof(help)-1)) < 0) { + if (errno == EINTR) + goto reread; + goto cleanup2; + } + help[got] = '\0'; + + if (sscanf(help, "QEMU PC emulator version %d.%d.%d", &major,&minor, µ) != 3) { + goto cleanup2; + } + + *version = (major * 1000 * 1000) + (minor * 1000) + micro; + if (strstr(help, "-no-kqemu")) + *flags |= QEMUD_CMD_FLAG_KQEMU; + if (*version >= 9000) + *flags |= QEMUD_CMD_FLAG_VNC_COLON; + ret = 0; + + qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d", + major, minor, micro, *version, *flags); + + cleanup2: + if (close(newstdout[0]) < 0) + ret = -1; + + rewait: + if (waitpid(child, &got, 0) != child) { + if (errno == EINTR) { + goto rewait; + } + qemudLog(QEMUD_ERR, "Unexpected exit status from qemu %d pid %lu", got, (unsigned long)child); + ret = -1; + } + /* Check & log unexpected exit status, but don't fail, + * as there's really no need to throw an error if we did + * actually read a valid version number above */ + if (WEXITSTATUS(got) != 1) { + qemudLog(QEMUD_WARN, "Unexpected exit status '%d', qemu probably failed", got); + } + + return ret; + } +} + +int qemudExtractVersion(struct qemud_server *server) { + char *binary = NULL; + + if (server->qemuVersion > 0) + return 0; + + if (!(binary = qemudLocateBinaryForArch(server, QEMUD_VIRT_QEMU, "i686"))) + return -1; + + if (qemudExtractVersionInfo(binary, &server->qemuVersion, &server->qemuCmdFlags) < 0) { + free(binary); + return -1; + } + + free(binary); + return 0; +} + + /* Parse the XML definition for a disk */ static struct qemud_vm_disk_def *qemudParseDiskXML(struct qemud_server *server, xmlNodePtr node) { @@ -950,9 +1057,13 @@ int qemudBuildCommandLine(struct qemud_server *server, struct qemud_vm_disk_def *disk = vm->def->disks; struct qemud_vm_net_def *net = vm->def->nets; + if (qemudExtractVersion(server) < 0) + return -1; + len = 1 + /* qemu */ 2 + /* machine type */ - (vm->def->virtType == QEMUD_VIRT_QEMU ? 1 : 0) + /* Disable kqemu */ + (((server->qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) && + (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*/ @@ -977,9 +1088,10 @@ int qemudBuildCommandLine(struct qemud_server *server, goto no_memory; if (!((*argv)[++n] = strdup(vm->def->os.machine))) goto no_memory; - if (vm->def->virtType == QEMUD_VIRT_QEMU) { + if ((server->qemuCmdFlags & QEMUD_CMD_FLAG_KQEMU) && + (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; @@ -996,8 +1108,8 @@ int qemudBuildCommandLine(struct qemud_server *server, 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++) { @@ -1103,7 +1215,14 @@ int qemudBuildCommandLine(struct qemud_server *server, 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->qemuCmdFlags & QEMUD_CMD_FLAG_VNC_COLON) ? + ":%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))) diff --git a/qemud/conf.h b/qemud/conf.h index 9069ee6842..60b39f50d7 100644 --- a/qemud/conf.h +++ b/qemud/conf.h @@ -26,6 +26,7 @@ #include "internal.h" +int qemudExtractVersion (struct qemud_server *server); int qemudBuildCommandLine (struct qemud_server *server, struct qemud_vm *vm, char ***argv); diff --git a/qemud/driver.c b/qemud/driver.c index 1aa3b396a4..6074aa5236 100644 --- a/qemud/driver.c +++ b/qemud/driver.c @@ -260,6 +260,9 @@ struct qemud_vm *qemudFindVMByName(const struct qemud_server *server, } int qemudGetVersion(struct qemud_server *server) { + if (qemudExtractVersion(server) < 0) + return -1; + return server->qemuVersion; } diff --git a/qemud/internal.h b/qemud/internal.h index b18aed8fe3..e2b5b722c4 100644 --- a/qemud/internal.h +++ b/qemud/internal.h @@ -161,6 +161,13 @@ enum qemud_vm_grapics_type { QEMUD_GRAPHICS_VNC, }; +/* Internal flags to keep track of qemu command line capabilities */ +enum qemud_cmd_flags { + QEMUD_CMD_FLAG_KQEMU = 1, + QEMUD_CMD_FLAG_VNC_COLON = 2, +}; + + enum qemud_vm_features { QEMUD_FEATURE_ACPI = 1, }; @@ -289,6 +296,7 @@ struct qemud_server { int nsockets; struct qemud_socket *sockets; int qemuVersion; + int qemuCmdFlags; /* values from enum qemud_cmd_flags */ int nclients; struct qemud_client *clients; int sigread; diff --git a/qemud/qemud.c b/qemud/qemud.c index bcfc613b1d..77c104129f 100644 --- a/qemud/qemud.c +++ b/qemud/qemud.c @@ -459,8 +459,6 @@ static struct qemud_server *qemudInitialize(int sys, int sigread) { 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;