[libvirt] [PATCH 1/3] Re-factor qemu version parsing

This patch is purely re-factoring without any functional changes to make way for the next patch. The main thing achieved by the refactoring is that we now have easier access to the parenthesised string that KVM folks seem to delight in changing. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 92 +++++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 72 insertions(+), 20 deletions(-) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 2c1eefc..f6a8390 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -412,6 +412,73 @@ virCapsPtr qemudCapsInit(void) { return NULL; } +/* We parse the output of 'qemu -help' to get the QEMU + * version number. The first bit is easy, just parse + * 'QEMU PC emulator version x.y.z'. + * + * With qemu-kvm, however, that is followed by a kvm-XX + * string in parenthesis. + */ +#define QEMU_VERSION_STR "QEMU PC emulator version " +#define KVM_VER_PREFIX " (kvm-" + +static int qemudParseVersionStr(const char *str, + unsigned int *version, + unsigned int *kvm_version) +{ + unsigned major, minor, micro; + const char *p = str; + + *version = *kvm_version = 0; + + if (!STRPREFIX(p, QEMU_VERSION_STR)) + goto fail; + + p += strlen(QEMU_VERSION_STR); + + major = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + minor = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + micro = virParseNumber(&p); + if (major == -1) + goto fail; + + if (STRPREFIX(p, KVM_VER_PREFIX)) { + int ret; + + p += strlen(KVM_VER_PREFIX); + + ret = virParseNumber(&p); + if (ret == -1) + goto fail; + + *kvm_version = ret; + } + + *version = (major * 1000 * 1000) + (minor * 1000) + micro; + + qemudDebug("Version %d.%d.%d - cooked version: %d", + major, minor, micro, *version); + if (*kvm_version) + qemudDebug("KVM version %d detected", *kvm_version); + + return 0; + +fail: + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse QEMU version number in '%s'"), + str); + return -1; +} int qemudExtractVersionInfo(const char *qemu, unsigned int *retversion, @@ -421,7 +488,6 @@ int qemudExtractVersionInfo(const char *qemu, pid_t child; int newstdout = -1; int ret = -1, status; - unsigned int major, minor, micro; unsigned int version, kvm_version; unsigned int flags = 0; @@ -443,22 +509,11 @@ int qemudExtractVersionInfo(const char *qemu, goto cleanup2; } - if (sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u)", - &major, &minor, µ, &kvm_version) != 4) - kvm_version = 0; + char *eol = strchr(help, '\n'); + if (eol) *eol = '\0'; - if (!kvm_version && - sscanf(help, "QEMU PC emulator version %u.%u.%u", - &major, &minor, µ) != 3) { - char *eol = strchr(help, '\n'); - if (eol) *eol = '\0'; - qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot parse QEMU version number in '%s'"), - help); + if (qemudParseVersionStr(help, &version, &kvm_version) == -1) goto cleanup2; - } - - version = (major * 1000 * 1000) + (minor * 1000) + micro; if (strstr(help, "-no-kqemu")) flags |= QEMUD_CMD_FLAG_KQEMU; @@ -512,10 +567,7 @@ int qemudExtractVersionInfo(const char *qemu, ret = 0; - qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d", - major, minor, micro, version, flags); - if (kvm_version) - qemudDebug("KVM version %d detected", kvm_version); + qemudDebug("QEMU supported cmdline flags = %d", flags); cleanup2: VIR_FREE(help); -- 1.6.0.6

The KVM version string can be one of the following: - qemu-kvm-x.y.z in stable releases - kvm-XX for kvm versions up to kvm-85 - qemu-kvm-devel-XX for kvm version kvm-86 and later There are only a few of places where we need to detect differences between KVM versions based on 0.9.1: 1) VNET_HDR introduced in kvm-74 2) -incoming tcp introduced in kvm-79 3) -incoming exec introduced in kvm-80 4) -incoming stdio in all earlier kvm versions With qemu-kvm-0.10.x, we can now assume that (1) is available if it's a KVM release, (2) and (3) is always available and (4) is never available. So, from now on we should only need to check the qemu version number and the "is_kvm" flag for detecting feature availability. We only need the KVM version number for older releases. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 39 ++++++++++++++++++++++++++++----------- 1 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index f6a8390..ea0d2f9 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -416,20 +416,30 @@ virCapsPtr qemudCapsInit(void) { * version number. The first bit is easy, just parse * 'QEMU PC emulator version x.y.z'. * - * With qemu-kvm, however, that is followed by a kvm-XX - * string in parenthesis. + * With qemu-kvm, however, that is followed by a string + * in parenthesis as follows: + * - qemu-kvm-x.y.z in stable releases + * - kvm-XX for kvm versions up to kvm-85 + * - qemu-kvm-devel-XX for kvm version kvm-86 and later + * + * For qemu-kvm versions before 0.10.z, we need to detect + * the KVM version number for some features. With 0.10.z + * and later, we just need the QEMU version number and + * whether it is KVM QEMU or mainline QEMU. */ #define QEMU_VERSION_STR "QEMU PC emulator version " +#define QEMU_KVM_VER_PREFIX " (qemu-kvm-" #define KVM_VER_PREFIX " (kvm-" static int qemudParseVersionStr(const char *str, unsigned int *version, + unsigned int *is_kvm, unsigned int *kvm_version) { unsigned major, minor, micro; const char *p = str; - *version = *kvm_version = 0; + *version = *is_kvm = *kvm_version = 0; if (!STRPREFIX(p, QEMU_VERSION_STR)) goto fail; @@ -452,9 +462,13 @@ static int qemudParseVersionStr(const char *str, if (major == -1) goto fail; - if (STRPREFIX(p, KVM_VER_PREFIX)) { + if (STRPREFIX(p, QEMU_KVM_VER_PREFIX)) { + *is_kvm = 1; + p += strlen(QEMU_KVM_VER_PREFIX); + } else if (STRPREFIX(p, KVM_VER_PREFIX)) { int ret; + *is_kvm = 1; p += strlen(KVM_VER_PREFIX); ret = virParseNumber(&p); @@ -470,6 +484,8 @@ static int qemudParseVersionStr(const char *str, major, minor, micro, *version); if (*kvm_version) qemudDebug("KVM version %d detected", *kvm_version); + else if (*is_kvm) + qemudDebug("qemu-kvm version %d.%d.%d detected", major, minor, micro); return 0; @@ -488,7 +504,7 @@ int qemudExtractVersionInfo(const char *qemu, pid_t child; int newstdout = -1; int ret = -1, status; - unsigned int version, kvm_version; + unsigned int version, is_kvm, kvm_version; unsigned int flags = 0; if (retflags) @@ -512,7 +528,7 @@ int qemudExtractVersionInfo(const char *qemu, char *eol = strchr(help, '\n'); if (eol) *eol = '\0'; - if (qemudParseVersionStr(help, &version, &kvm_version) == -1) + if (qemudParseVersionStr(help, &version, &is_kvm, &kvm_version) == -1) goto cleanup2; if (strstr(help, "-no-kqemu")) @@ -536,7 +552,8 @@ int qemudExtractVersionInfo(const char *qemu, flags |= QEMUD_CMD_FLAG_DRIVE_BOOT; if (version >= 9000) flags |= QEMUD_CMD_FLAG_VNC_COLON; - if (kvm_version >= 74) + + if (is_kvm && (version >= 10000 || kvm_version >= 74)) flags |= QEMUD_CMD_FLAG_VNET_HDR; /* @@ -549,15 +566,15 @@ int qemudExtractVersionInfo(const char *qemu, * was broken, because it blocked the monitor console * while waiting for data, so pretend it doesn't exist */ - if (kvm_version >= 79) { + if (version >= 10000) { + flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP; + flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; + } else if (kvm_version >= 79) { flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP; if (kvm_version >= 80) flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; } else if (kvm_version > 0) { flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO; - } else if (version >= 10000) { - flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP; - flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; } if (retversion) -- 1.6.0.6

Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 8 ++-- src/qemu_conf.h | 5 +++ tests/Makefile.am | 9 +++-- tests/qemuvertest.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 tests/qemuvertest.c diff --git a/src/qemu_conf.c b/src/qemu_conf.c index ea0d2f9..4edfedb 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -431,10 +431,10 @@ virCapsPtr qemudCapsInit(void) { #define QEMU_KVM_VER_PREFIX " (qemu-kvm-" #define KVM_VER_PREFIX " (kvm-" -static int qemudParseVersionStr(const char *str, - unsigned int *version, - unsigned int *is_kvm, - unsigned int *kvm_version) +int qemudParseVersionStr(const char *str, + unsigned int *version, + unsigned int *is_kvm, + unsigned int *kvm_version) { unsigned major, minor, micro; const char *p = str; diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 1001e00..40a4a97 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -125,6 +125,11 @@ int qemudExtractVersionInfo (const char *qemu, unsigned int *version, unsigned int *flags); +int qemudParseVersionStr (const char *str, + unsigned int *version, + unsigned int *is_kvm, + unsigned int *kvm_version); + int qemudBuildCommandLine (virConnectPtr conn, struct qemud_driver *driver, virDomainDefPtr def, diff --git a/tests/Makefile.am b/tests/Makefile.am index 621a0be..3cf06a8 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -61,7 +61,7 @@ noinst_PROGRAMS += xml2sexprtest sexpr2xmltest \ reconnect xmconfigtest xencapstest endif if WITH_QEMU -noinst_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest +noinst_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuvertest endif if WITH_SECDRIVER_SELINUX @@ -119,7 +119,7 @@ endif endif if WITH_QEMU -TESTS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest +TESTS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuvertest endif if WITH_SECDRIVER_SELINUX @@ -199,8 +199,11 @@ qemuargv2xmltest_SOURCES = \ qemuargv2xmltest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h qemuargv2xmltest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS) + +qemuvertest_SOURCES = qemuvertest.c testutils.c testutils.h +qemuvertest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS) else -EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c testutilsqemu.c testutilsqemu.h +EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c qemuvertest.c testutilsqemu.c testutilsqemu.h endif nodedevxml2xmltest_SOURCES = \ diff --git a/tests/qemuvertest.c b/tests/qemuvertest.c new file mode 100644 index 0000000..bc9b7d6 --- /dev/null +++ b/tests/qemuvertest.c @@ -0,0 +1,89 @@ +#include <config.h> + +#ifdef WITH_QEMU + +#include <stdio.h> +#include <stdlib.h> + +#include "testutils.h" +#include "qemu_conf.h" + +struct testInfo { + const char *name; + const char *str; + unsigned version; + unsigned is_kvm; + unsigned kvm_version; +}; + +static char *progname; + +static int testVersionParsing(const void *data) +{ + const struct testInfo *info = data; + unsigned version, is_kvm, kvm_version; + + if (qemudParseVersionStr(info->str, &version, &is_kvm, &kvm_version) == -1) { + fprintf(stderr, "Failed to parse version string '%s'\n", info->str); + return -1; + } + + if (version != info->version) { + fprintf(stderr, "Parsed versions do not match: got %u, expected %u\n", + version, info->version); + return -1; + } + + if (is_kvm != info->is_kvm) { + fprintf(stderr, "Parsed is_kvm flag does not match: got %u, expected %u\n", + is_kvm, info->is_kvm); + return -1; + } + + if (kvm_version != kvm_version) { + fprintf(stderr, "Parsed KVM versions do not match: got %u, expected %u\n", + version, kvm_version); + return -1; + } + + return 0; + +} + +static int +mymain(int argc, char **argv) +{ + int ret = 0; + + progname = argv[0]; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", progname); + return (EXIT_FAILURE); + } + +#define DO_TEST(name, str, version, is_kvm, kvm_version) \ + do { \ + const struct testInfo info = { name, str, version, is_kvm, kvm_version }; \ + if (virtTestRun("QEMU Version Parse " name, \ + 1, testVersionParsing, &info) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST("qemu-0.9.1", "QEMU PC emulator version 0.9.1,", 9001, 0, 0); + DO_TEST("kvm-74", "QEMU PC emulator version 0.9.1 (kvm-74),", 9001, 1, 74); + DO_TEST("qemu-0.10.1", "QEMU PC emulator version 0.10.1,", 10001, 0, 0); + DO_TEST("qemu-kvm-0.10.4", "QEMU PC emulator version 0.10.4 (qemu-kvm-0.10.4),", 10004, 1, 0); + DO_TEST("kvm-85", "QEMU PC emulator version 0.10.50 (kvm-85),", 10050, 1, 85); + DO_TEST("kvm-86", "QEMU PC emulator version 0.10.50 (qemu-kvm-devel-86),", 10050, 1, 0); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) + +#else + +int main (void) { return (77); /* means 'test skipped' for automake */ } + +#endif /* WITH_QEMU */ -- 1.6.0.6

On Wed, Jun 10, 2009 at 01:17:35PM +0100, Mark McLoughlin wrote:
This patch is purely re-factoring without any functional changes to make way for the next patch.
The main thing achieved by the refactoring is that we now have easier access to the parenthesised string that KVM folks seem to delight in changing.
int qemudExtractVersionInfo(const char *qemu, unsigned int *retversion, @@ -421,7 +488,6 @@ int qemudExtractVersionInfo(const char *qemu, pid_t child; int newstdout = -1; int ret = -1, status; - unsigned int major, minor, micro; unsigned int version, kvm_version; unsigned int flags = 0;
@@ -443,22 +509,11 @@ int qemudExtractVersionInfo(const char *qemu, goto cleanup2; }
- if (sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u)", - &major, &minor, µ, &kvm_version) != 4) - kvm_version = 0; + char *eol = strchr(help, '\n'); + if (eol) *eol = '\0';
IIUC this NULL terminates the 'help' string on the first line, which will surely break....
- if (!kvm_version && - sscanf(help, "QEMU PC emulator version %u.%u.%u", - &major, &minor, µ) != 3) { - char *eol = strchr(help, '\n'); - if (eol) *eol = '\0'; - qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot parse QEMU version number in '%s'"), - help); + if (qemudParseVersionStr(help, &version, &kvm_version) == -1) goto cleanup2; - } - - version = (major * 1000 * 1000) + (minor * 1000) + micro;
if (strstr(help, "-no-kqemu")) flags |= QEMUD_CMD_FLAG_KQEMU;
....this code which looks at subsequent lines of 'help' ? Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, 2009-06-10 at 13:21 +0100, Daniel P. Berrange wrote:
+ char *eol = strchr(help, '\n'); + if (eol) *eol = '\0';
IIUC this NULL terminates the 'help' string on the first line, which will surely break....
- if (!kvm_version && - sscanf(help, "QEMU PC emulator version %u.%u.%u", - &major, &minor, µ) != 3) { - char *eol = strchr(help, '\n'); - if (eol) *eol = '\0'; - qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot parse QEMU version number in '%s'"), - help); + if (qemudParseVersionStr(help, &version, &kvm_version) == -1) goto cleanup2; - } - - version = (major * 1000 * 1000) + (minor * 1000) + micro;
if (strstr(help, "-no-kqemu")) flags |= QEMUD_CMD_FLAG_KQEMU;
....this code which looks at subsequent lines of 'help' ?
Nice catch Dan, thanks. Another version coming up which includes tests for the flags computation, which would have caught this thinko. Cheers, Mark.

This patch is purely re-factoring without any functional changes to make way for the next patch. The main thing achieved by the refactoring is that we now have easier access to the parenthesised string that KVM folks seem to delight in changing. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 168 ++++++++++++++++++++++++++++++++++++++----------------- 1 files changed, 117 insertions(+), 51 deletions(-) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 2c1eefc..ce835aa 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -412,54 +412,12 @@ virCapsPtr qemudCapsInit(void) { return NULL; } - -int qemudExtractVersionInfo(const char *qemu, - unsigned int *retversion, - unsigned int *retflags) { - const char *const qemuarg[] = { qemu, "-help", NULL }; - const char *const qemuenv[] = { "LC_ALL=C", NULL }; - pid_t child; - int newstdout = -1; - int ret = -1, status; - unsigned int major, minor, micro; - unsigned int version, kvm_version; +static unsigned int qemudComputeCmdFlags(const char *help, + unsigned int version, + unsigned int kvm_version) +{ unsigned int flags = 0; - if (retflags) - *retflags = 0; - if (retversion) - *retversion = 0; - - if (virExec(NULL, qemuarg, qemuenv, NULL, - &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0) - return -1; - - char *help = NULL; - enum { MAX_HELP_OUTPUT_SIZE = 1024*64 }; - int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help); - if (len < 0) { - virReportSystemError(NULL, errno, "%s", - _("Unable to read QEMU help output")); - goto cleanup2; - } - - if (sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u)", - &major, &minor, µ, &kvm_version) != 4) - kvm_version = 0; - - if (!kvm_version && - sscanf(help, "QEMU PC emulator version %u.%u.%u", - &major, &minor, µ) != 3) { - char *eol = strchr(help, '\n'); - if (eol) *eol = '\0'; - qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot parse QEMU version number in '%s'"), - help); - goto cleanup2; - } - - version = (major * 1000 * 1000) + (minor * 1000) + micro; - if (strstr(help, "-no-kqemu")) flags |= QEMUD_CMD_FLAG_KQEMU; if (strstr(help, "-no-kvm")) @@ -505,6 +463,119 @@ int qemudExtractVersionInfo(const char *qemu, flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; } + return flags; +} + +/* We parse the output of 'qemu -help' to get the QEMU + * version number. The first bit is easy, just parse + * 'QEMU PC emulator version x.y.z'. + * + * With qemu-kvm, however, that is followed by a kvm-XX + * string in parenthesis. + */ +#define QEMU_VERSION_STR "QEMU PC emulator version " +#define KVM_VER_PREFIX " (kvm-" + +static int qemudParseHelpStr(const char *help, + unsigned int *flags, + unsigned int *version, + unsigned int *kvm_version) +{ + unsigned major, minor, micro; + const char *p = help; + + *flags = *version = *kvm_version = 0; + + if (!STRPREFIX(p, QEMU_VERSION_STR)) + goto fail; + + p += strlen(QEMU_VERSION_STR); + + major = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + minor = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + micro = virParseNumber(&p); + if (major == -1) + goto fail; + + if (STRPREFIX(p, KVM_VER_PREFIX)) { + int ret; + + p += strlen(KVM_VER_PREFIX); + + ret = virParseNumber(&p); + if (ret == -1) + goto fail; + + *kvm_version = ret; + } + + *version = (major * 1000 * 1000) + (minor * 1000) + micro; + + *flags = qemudComputeCmdFlags(help, *version, *kvm_version); + + qemudDebug("Version %u.%u.%u, cooked version %u, flags %u", + major, minor, micro, *version, *flags); + if (*kvm_version) + qemudDebug("KVM version %u detected", *kvm_version); + + return 0; + +fail: + p = strchr(help, '\n'); + if (p) + p = strndup(help, p - help); + + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse QEMU version number in '%s'"), + p ? p : help); + + VIR_FREE(p); + + return -1; +} + +int qemudExtractVersionInfo(const char *qemu, + unsigned int *retversion, + unsigned int *retflags) { + const char *const qemuarg[] = { qemu, "-help", NULL }; + const char *const qemuenv[] = { "LC_ALL=C", NULL }; + pid_t child; + int newstdout = -1; + int ret = -1, status; + unsigned int version, kvm_version; + unsigned int flags = 0; + + if (retflags) + *retflags = 0; + if (retversion) + *retversion = 0; + + if (virExec(NULL, qemuarg, qemuenv, NULL, + &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0) + return -1; + + char *help = NULL; + enum { MAX_HELP_OUTPUT_SIZE = 1024*64 }; + int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help); + if (len < 0) { + virReportSystemError(NULL, errno, "%s", + _("Unable to read QEMU help output")); + goto cleanup2; + } + + if (qemudParseHelpStr(help, &version, &kvm_version, &flags) == -1) + goto cleanup2; + if (retversion) *retversion = version; if (retflags) @@ -512,11 +583,6 @@ int qemudExtractVersionInfo(const char *qemu, ret = 0; - qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d", - major, minor, micro, version, flags); - if (kvm_version) - qemudDebug("KVM version %d detected", kvm_version); - cleanup2: VIR_FREE(help); if (close(newstdout) < 0) -- 1.6.0.6

The KVM version string can be one of the following: - qemu-kvm-x.y.z in stable releases - kvm-XX for kvm versions up to kvm-85 - qemu-kvm-devel-XX for kvm version kvm-86 and later There are only a few of places where we need to detect differences between KVM versions based on 0.9.1: 1) VNET_HDR introduced in kvm-74 2) -incoming tcp introduced in kvm-79 3) -incoming exec introduced in kvm-80 4) -incoming stdio in all earlier kvm versions With qemu-kvm-0.10.x, we can now assume that (1) is available if it's a KVM release, (2) and (3) is always available and (4) is never available. So, from now on we should only need to check the qemu version number and the "is_kvm" flag for detecting feature availability. We only need the KVM version number for older releases. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 44 +++++++++++++++++++++++++++++++------------- 1 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index ce835aa..9ff1402 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -414,6 +414,7 @@ virCapsPtr qemudCapsInit(void) { static unsigned int qemudComputeCmdFlags(const char *help, unsigned int version, + unsigned int is_kvm, unsigned int kvm_version) { unsigned int flags = 0; @@ -439,7 +440,8 @@ static unsigned int qemudComputeCmdFlags(const char *help, flags |= QEMUD_CMD_FLAG_DRIVE_BOOT; if (version >= 9000) flags |= QEMUD_CMD_FLAG_VNC_COLON; - if (kvm_version >= 74) + + if (is_kvm && (version >= 10000 || kvm_version >= 74)) flags |= QEMUD_CMD_FLAG_VNET_HDR; /* @@ -452,15 +454,15 @@ static unsigned int qemudComputeCmdFlags(const char *help, * was broken, because it blocked the monitor console * while waiting for data, so pretend it doesn't exist */ - if (kvm_version >= 79) { + if (version >= 10000) { + flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP; + flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; + } else if (kvm_version >= 79) { flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP; if (kvm_version >= 80) flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; } else if (kvm_version > 0) { flags |= QEMUD_CMD_FLAG_MIGRATE_KVM_STDIO; - } else if (version >= 10000) { - flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_TCP; - flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; } return flags; @@ -470,21 +472,31 @@ static unsigned int qemudComputeCmdFlags(const char *help, * version number. The first bit is easy, just parse * 'QEMU PC emulator version x.y.z'. * - * With qemu-kvm, however, that is followed by a kvm-XX - * string in parenthesis. + * With qemu-kvm, however, that is followed by a string + * in parenthesis as follows: + * - qemu-kvm-x.y.z in stable releases + * - kvm-XX for kvm versions up to kvm-85 + * - qemu-kvm-devel-XX for kvm version kvm-86 and later + * + * For qemu-kvm versions before 0.10.z, we need to detect + * the KVM version number for some features. With 0.10.z + * and later, we just need the QEMU version number and + * whether it is KVM QEMU or mainline QEMU. */ #define QEMU_VERSION_STR "QEMU PC emulator version " +#define QEMU_KVM_VER_PREFIX " (qemu-kvm-" #define KVM_VER_PREFIX " (kvm-" static int qemudParseHelpStr(const char *help, unsigned int *flags, unsigned int *version, + unsigned int *is_kvm, unsigned int *kvm_version) { unsigned major, minor, micro; const char *p = help; - *flags = *version = *kvm_version = 0; + *flags = *version = *is_kvm = *kvm_version = 0; if (!STRPREFIX(p, QEMU_VERSION_STR)) goto fail; @@ -507,9 +519,13 @@ static int qemudParseHelpStr(const char *help, if (major == -1) goto fail; - if (STRPREFIX(p, KVM_VER_PREFIX)) { + if (STRPREFIX(p, QEMU_KVM_VER_PREFIX)) { + *is_kvm = 1; + p += strlen(QEMU_KVM_VER_PREFIX); + } else if (STRPREFIX(p, KVM_VER_PREFIX)) { int ret; + *is_kvm = 1; p += strlen(KVM_VER_PREFIX); ret = virParseNumber(&p); @@ -521,12 +537,14 @@ static int qemudParseHelpStr(const char *help, *version = (major * 1000 * 1000) + (minor * 1000) + micro; - *flags = qemudComputeCmdFlags(help, *version, *kvm_version); + *flags = qemudComputeCmdFlags(help, *version, *is_kvm, *kvm_version); qemudDebug("Version %u.%u.%u, cooked version %u, flags %u", major, minor, micro, *version, *flags); if (*kvm_version) - qemudDebug("KVM version %u detected", *kvm_version); + qemudDebug("KVM version %d detected", *kvm_version); + else if (*is_kvm) + qemudDebug("qemu-kvm version %u.%u.%u detected", major, minor, micro); return 0; @@ -552,7 +570,7 @@ int qemudExtractVersionInfo(const char *qemu, pid_t child; int newstdout = -1; int ret = -1, status; - unsigned int version, kvm_version; + unsigned int version, is_kvm, kvm_version; unsigned int flags = 0; if (retflags) @@ -573,7 +591,7 @@ int qemudExtractVersionInfo(const char *qemu, goto cleanup2; } - if (qemudParseHelpStr(help, &version, &kvm_version, &flags) == -1) + if (qemudParseHelpStr(help, &version, &kvm_version, &is_kvm, &flags) == -1) goto cleanup2; if (retversion) -- 1.6.0.6

Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 10 +- src/qemu_conf.h | 6 ++ tests/Makefile.am | 9 ++- tests/qemuhelpdata/kvm-74 | 111 +++++++++++++++++++++++ tests/qemuhelpdata/kvm-86 | 170 ++++++++++++++++++++++++++++++++++++ tests/qemuhelpdata/qemu-0.10.5 | 141 +++++++++++++++++++++++++++++ tests/qemuhelpdata/qemu-0.9.1 | 102 +++++++++++++++++++++ tests/qemuhelpdata/qemu-kvm-0.10.5 | 155 ++++++++++++++++++++++++++++++++ tests/qemuhelptest.c | 107 ++++++++++++++++++++++ 9 files changed, 803 insertions(+), 8 deletions(-) create mode 100644 tests/qemuhelpdata/kvm-74 create mode 100644 tests/qemuhelpdata/kvm-86 create mode 100644 tests/qemuhelpdata/qemu-0.10.5 create mode 100644 tests/qemuhelpdata/qemu-0.9.1 create mode 100644 tests/qemuhelpdata/qemu-kvm-0.10.5 create mode 100644 tests/qemuhelptest.c diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 9ff1402..7cce633 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -487,11 +487,11 @@ static unsigned int qemudComputeCmdFlags(const char *help, #define QEMU_KVM_VER_PREFIX " (qemu-kvm-" #define KVM_VER_PREFIX " (kvm-" -static int qemudParseHelpStr(const char *help, - unsigned int *flags, - unsigned int *version, - unsigned int *is_kvm, - unsigned int *kvm_version) +int qemudParseHelpStr(const char *help, + unsigned int *flags, + unsigned int *version, + unsigned int *is_kvm, + unsigned int *kvm_version) { unsigned major, minor, micro; const char *p = help; diff --git a/src/qemu_conf.h b/src/qemu_conf.h index 1001e00..b01fe48 100644 --- a/src/qemu_conf.h +++ b/src/qemu_conf.h @@ -125,6 +125,12 @@ int qemudExtractVersionInfo (const char *qemu, unsigned int *version, unsigned int *flags); +int qemudParseHelpStr (const char *str, + unsigned int *flags, + unsigned int *version, + unsigned int *is_kvm, + unsigned int *kvm_version); + int qemudBuildCommandLine (virConnectPtr conn, struct qemud_driver *driver, virDomainDefPtr def, diff --git a/tests/Makefile.am b/tests/Makefile.am index 621a0be..3d98d69 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -61,7 +61,7 @@ noinst_PROGRAMS += xml2sexprtest sexpr2xmltest \ reconnect xmconfigtest xencapstest endif if WITH_QEMU -noinst_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest +noinst_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuhelptest endif if WITH_SECDRIVER_SELINUX @@ -119,7 +119,7 @@ endif endif if WITH_QEMU -TESTS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest +TESTS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuhelptest endif if WITH_SECDRIVER_SELINUX @@ -199,8 +199,11 @@ qemuargv2xmltest_SOURCES = \ qemuargv2xmltest.c testutilsqemu.c testutilsqemu.h \ testutils.c testutils.h qemuargv2xmltest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS) + +qemuhelptest_SOURCES = qemuhelptest.c testutils.c testutils.h +qemuhelptest_LDADD = ../src/libvirt_driver_qemu.la $(LDADDS) else -EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c testutilsqemu.c testutilsqemu.h +EXTRA_DIST += qemuxml2argvtest.c qemuxml2xmltest.c qemuargv2xmltest.c qemuhelptest.c testutilsqemu.c testutilsqemu.h endif nodedevxml2xmltest_SOURCES = \ diff --git a/tests/qemuhelpdata/kvm-74 b/tests/qemuhelpdata/kvm-74 new file mode 100644 index 0000000..f44932d --- /dev/null +++ b/tests/qemuhelpdata/kvm-74 @@ -0,0 +1,111 @@ +QEMU PC emulator version 0.9.1 (kvm-74), Copyright (c) 2003-2008 Fabrice Bellard +usage: qemu [options] [disk_image] + +'disk_image' is a raw hard image image for IDE hard disk 0 + +Standard options: +-M machine select emulated machine (-M ? for list) +-cpu cpu select CPU (-cpu ? for list) +-fda/-fdb file use 'file' as floppy disk 0/1 image +-hda/-hdb file use 'file' as IDE hard disk 0/1 image +-hdc/-hdd file use 'file' as IDE hard disk 2/3 image +-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master) +-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i] + [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off] + [,cache=on|off][,format=f][,boot=on|off] + use 'file' as a drive image +-mtdblock file use 'file' as on-board Flash memory image +-sd file use 'file' as SecureDigital card image +-pflash file use 'file' as a parallel flash image +-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n) +-snapshot write to temporary files instead of disk image files +-no-frame open SDL window without a frame and window decorations +-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt) +-no-quit disable SDL window close capability +-no-fd-bootchk disable boot signature checking for floppy disks +-m megs set virtual RAM size to megs MB [default=128] +-smp n set the number of CPUs to 'n' [default=1] +-nographic disable graphical output and redirect serial I/Os to console +-portrait rotate graphical output 90 deg left (only PXA LCD) +-k language use keyboard layout (for example "fr" for French) +-audio-help print list of audio drivers and their options +-soundhw c1,... enable audio support + and only specified sound cards (comma separated list) + use -soundhw ? to get the list of supported cards + use -soundhw all to enable all of them +-localtime set the real time clock to local time [default=utc] +-full-screen start in full screen +-win2k-hack use it when installing Windows 2000 to avoid a disk full bug +-usb enable the USB driver (will be the default soon) +-usbdevice name add the host or guest USB device 'name' +-name string set the name of the guest + +Network options: +-net nic[,vlan=n][,macaddr=addr][,model=type] + create a new Network Interface Card and connect it to VLAN 'n' +-net user[,vlan=n][,hostname=host] + connect the user mode network stack to VLAN 'n' and send + hostname 'host' to DHCP clients +-net tap[,vlan=n][,fd=h][,ifname=name][,script=file][,downscript=dfile] + connect the host TAP network interface to VLAN 'n' and use the + network scripts 'file' (default=/etc/qemu-ifup) + and 'dfile' (default=/etc/qemu-ifdown); + use '[down]script=no' to disable script execution; + use 'fd=h' to connect to an already opened TAP interface +-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port] + connect the vlan 'n' to another VLAN using a socket connection +-net socket[,vlan=n][,fd=h][,mcast=maddr:port] + connect the vlan 'n' to multicast maddr and port +-net none use it alone to have zero network devices; if no -net option + is provided, the default is '-net nic -net user' + +-tftp dir allow tftp access to files in dir [-net user] +-bootp file advertise file in BOOTP replies +-smb dir allow SMB access to files in 'dir' [-net user] +-redir [tcp|udp]:host-port:[guest-host]:guest-port + redirect TCP or UDP connections from host to guest [-net user] + +Linux boot specific: +-kernel bzImage use 'bzImage' as kernel image +-append cmdline use 'cmdline' as kernel command line +-initrd file use 'file' as initial ram disk + +Debug/Expert options: +-monitor dev redirect the monitor to char device 'dev' +-serial dev redirect the serial port to char device 'dev' +-parallel dev redirect the parallel port to char device 'dev' +-pidfile file Write PID to 'file' +-S freeze CPU at startup (use 'c' to start execution) +-s wait gdb connection to port +-p port set gdb connection port [default=1234] +-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) +-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS + translation (t=none or lba) (usually qemu can guess them) +-L path set the directory for the BIOS, VGA BIOS and keymaps +-no-kvm disable KVM hardware virtualization +-no-kvm-irqchip disable KVM kernel mode PIC/IOAPIC/LAPIC +-no-kvm-pit disable KVM kernel mode PIT +-std-vga simulate a standard VGA card with VESA Bochs Extensions + (default is CL-GD5446 PCI VGA) +-no-acpi disable ACPI +-no-reboot exit instead of rebooting +-no-shutdown stop before shutdown +-loadvm [tag|id] start right away with a saved state (loadvm in monitor) +-vnc display start a VNC server on display +-daemonize daemonize QEMU after initializing +-tdf inject timer interrupts that got lost +-kvm-shadow-memory megs set the amount of shadow pages to be allocated +-mem-path set the path to hugetlbfs/tmpfs mounted directory, also enables allocation of guest memory with huge pages +-option-rom rom load a file, rom, into the option ROM space +-clock force the use of the given methods for timer alarm. + To see what timers are available use -clock ? +-startdate select initial date of the clock +-icount [N|auto] + Enable virtual instruction counter with 2^N clock ticks per instruction + +During emulation, the following keys are useful: +ctrl-alt-f toggle full screen +ctrl-alt-n switch to virtual console 'n' +ctrl-alt toggle mouse and keyboard grab + +When using -nographic, press 'ctrl-a h' to get some help. diff --git a/tests/qemuhelpdata/kvm-86 b/tests/qemuhelpdata/kvm-86 new file mode 100644 index 0000000..1687cab --- /dev/null +++ b/tests/qemuhelpdata/kvm-86 @@ -0,0 +1,170 @@ +QEMU PC emulator version 0.10.50 (qemu-kvm-devel-86), Copyright (c) 2003-2008 Fabrice Bellard +usage: qemu [options] [disk_image] + +'disk_image' is a raw hard image image for IDE hard disk 0 + +Standard options: +-h or -help display this help and exit +-version display version information and exit +-M machine select emulated machine (-M ? for list) +-cpu cpu select CPU (-cpu ? for list) +-smp n set the number of CPUs to 'n' [default=1] +-numa node[,mem=size][,cpus=cpu[-cpu]][,nodeid=node] +-fda/-fdb file use 'file' as floppy disk 0/1 image +-hda/-hdb file use 'file' as IDE hard disk 0/1 image +-hdc/-hdd file use 'file' as IDE hard disk 2/3 image +-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master) +-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i] + [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off] + [,cache=writethrough|writeback|none][,format=f][,serial=s] + [,boot=on|off] + use 'file' as a drive image +-mtdblock file use 'file' as on-board Flash memory image +-sd file use 'file' as SecureDigital card image +-pflash file use 'file' as a parallel flash image +-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n) +-snapshot write to temporary files instead of disk image files +-m megs set virtual RAM size to megs MB [default=128] +-k language use keyboard layout (for example 'fr' for French) +-audio-help print list of audio drivers and their options +-soundhw c1,... enable audio support + and only specified sound cards (comma separated list) + use -soundhw ? to get the list of supported cards + use -soundhw all to enable all of them +-usb enable the USB driver (will be the default soon) +-usbdevice name add the host or guest USB device 'name' +-name string set the name of the guest +-uuid %08x-%04x-%04x-%04x-%012x + specify machine UUID + +Display options: +-nographic disable graphical output and redirect serial I/Os to console +-no-frame open SDL window without a frame and window decorations +-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt) +-no-quit disable SDL window close capability +-sdl enable SDL +-portrait rotate graphical output 90 deg left (only PXA LCD) +-vga [std|cirrus|vmware|xenfb|none] + select video card type +-full-screen start in full screen +-vnc display start a VNC server on display + +i386 target only: +-win2k-hack use it when installing Windows 2000 to avoid a disk full bug +-rtc-td-hack use it to fix time drift in Windows ACPI HAL +-no-fd-bootchk disable boot signature checking for floppy disks +-no-acpi disable ACPI +-no-hpet disable HPET +-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...] + ACPI table description +-smbios file=binary + Load SMBIOS entry from binary file +-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d] + Specify SMBIOS type 0 fields +-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str] + [,uuid=uuid][,sku=str][,family=str] + Specify SMBIOS type 1 fields + +Network options: +-net nic[,vlan=n][,macaddr=addr][,model=type][,name=str] + create a new Network Interface Card and connect it to VLAN 'n' +-net user[,vlan=n][,name=str][,hostname=host] + connect the user mode network stack to VLAN 'n' and send + hostname 'host' to DHCP clients +-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile] + connect the host TAP network interface to VLAN 'n' and use the + network scripts 'file' (default=/etc/qemu-ifup) + and 'dfile' (default=/etc/qemu-ifdown); + use '[down]script=no' to disable script execution; + use 'fd=h' to connect to an already opened TAP interface +-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port] + connect the vlan 'n' to another VLAN using a socket connection +-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port] + connect the vlan 'n' to multicast maddr and port +-net dump[,vlan=n][,file=f][,len=n] + dump traffic on vlan 'n' to file 'f' (max n bytes per packet) +-net none use it alone to have zero network devices; if no -net option + is provided, the default is '-net nic -net user' +-tftp dir allow tftp access to files in dir [-net user] +-bootp file advertise file in BOOTP replies +-smb dir allow SMB access to files in 'dir' [-net user] +-redir [tcp|udp]:host-port:[guest-host]:guest-port + redirect TCP or UDP connections from host to guest [-net user] + +-bt hci,null dumb bluetooth HCI - doesn't respond to commands +-bt hci,host[:id] + use host's HCI with the given name +-bt hci[,vlan=n] + emulate a standard HCI in virtual scatternet 'n' +-bt vhci[,vlan=n] + add host computer to virtual scatternet 'n' using VHCI +-bt device:dev[,vlan=n] + emulate a bluetooth device 'dev' in scatternet 'n' + +Linux boot specific: +-kernel bzImage use 'bzImage' as kernel image +-append cmdline use 'cmdline' as kernel command line +-initrd file use 'file' as initial ram disk + +Debug/Expert options: +-serial dev redirect the serial port to char device 'dev' +-parallel dev redirect the parallel port to char device 'dev' +-monitor dev redirect the monitor to char device 'dev' +-pidfile file write PID to 'file' +-singlestep always run in singlestep mode +-S freeze CPU at startup (use 'c' to start execution) +-gdb dev wait for gdb connection on 'dev' +-s shorthand for -gdb tcp::1234 +-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) +-hdachs c,h,s[,t] + force hard disk 0 physical geometry and the optional BIOS + translation (t=none or lba) (usually qemu can guess them) +-L path set the directory for the BIOS, VGA BIOS and keymaps +-bios file set the filename for the BIOS +-no-reboot exit instead of rebooting +-no-shutdown stop before shutdown +-loadvm [tag|id] + start right away with a saved state (loadvm in monitor) +-daemonize daemonize QEMU after initializing +-option-rom rom load a file, rom, into the option ROM space +-clock force the use of the given methods for timer alarm. + To see what timers are available use -clock ? +-localtime set the real time clock to local time [default=utc] +-startdate select initial date of the clock +-icount [N|auto] + enable virtual instruction counter with 2^N clock ticks per + instruction +-watchdog i6300esb|ib700 + enable virtual hardware watchdog [default=none] +-watchdog-action reset|shutdown|poweroff|pause|debug|none + action when watchdog fires [default=reset] +-echr chr set terminal escape character instead of ctrl-a +-virtioconsole c + set virtio console +-show-cursor show cursor +-tb-size n set TB size +-incoming p prepare for incoming migration, listen on port p +-chroot dir Chroot to dir just before starting the VM. +-runas user Change to user id user just before starting the VM. +-no-kvm disable KVM hardware virtualization +-no-kvm-irqchip disable KVM kernel mode PIC/IOAPIC/LAPIC +-no-kvm-pit disable KVM kernel mode PIT +-no-kvm-pit-reinjection disable KVM kernel mode PIT interrupt reinjection +-pcidevice host=bus:dev.func[,dma=none][,name=string] + expose a PCI device to the guest OS. + dma=none: don't perform any dma translations (default is to use an iommu) + 'string' is used in log output. +-enable-nesting enable support for running a VM inside the VM (AMD only) +-nvram FILE provide ia64 nvram contents +-tdf enable guest time drift compensation +-kvm-shadow-memory MEGABYTES + allocate MEGABYTES for kvm mmu shadowing +-mempath FILE provide backing storage for guest RAM +-mem-prealloc preallocate guest memory (use with -mempath) + +During emulation, the following keys are useful: +ctrl-alt-f toggle full screen +ctrl-alt-n switch to virtual console 'n' +ctrl-alt toggle mouse and keyboard grab + +When using -nographic, press 'ctrl-a h' to get some help. diff --git a/tests/qemuhelpdata/qemu-0.10.5 b/tests/qemuhelpdata/qemu-0.10.5 new file mode 100644 index 0000000..2a8363b --- /dev/null +++ b/tests/qemuhelpdata/qemu-0.10.5 @@ -0,0 +1,141 @@ +QEMU PC emulator version 0.10.5, Copyright (c) 2003-2008 Fabrice Bellard +usage: qemu [options] [disk_image] + +'disk_image' is a raw hard image image for IDE hard disk 0 + +Standard options: +-h or -help display this help and exit +-M machine select emulated machine (-M ? for list) +-cpu cpu select CPU (-cpu ? for list) +-smp n set the number of CPUs to 'n' [default=1] +-fda/-fdb file use 'file' as floppy disk 0/1 image +-hda/-hdb file use 'file' as IDE hard disk 0/1 image +-hdc/-hdd file use 'file' as IDE hard disk 2/3 image +-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master) +-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i] + [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off] + [,cache=writethrough|writeback|none][,format=f][,serial=s] + use 'file' as a drive image +-mtdblock file use 'file' as on-board Flash memory image +-sd file use 'file' as SecureDigital card image +-pflash file use 'file' as a parallel flash image +-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n) +-snapshot write to temporary files instead of disk image files +-m megs set virtual RAM size to megs MB [default=128] +-k language use keyboard layout (for example "fr" for French) +-audio-help print list of audio drivers and their options +-soundhw c1,... enable audio support + and only specified sound cards (comma separated list) + use -soundhw ? to get the list of supported cards + use -soundhw all to enable all of them +-usb enable the USB driver (will be the default soon) +-usbdevice name add the host or guest USB device 'name' +-name string set the name of the guest +-uuid %08x-%04x-%04x-%04x-%012x + specify machine UUID + +Display options: +-nographic disable graphical output and redirect serial I/Os to console +-curses use a curses/ncurses interface instead of SDL +-no-frame open SDL window without a frame and window decorations +-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt) +-no-quit disable SDL window close capability +-sdl enable SDL +-portrait rotate graphical output 90 deg left (only PXA LCD) +-vga [std|cirrus|vmware|none] + select video card type +-full-screen start in full screen +-vnc display start a VNC server on display + +Network options: +-net nic[,vlan=n][,macaddr=addr][,model=type][,name=str] + create a new Network Interface Card and connect it to VLAN 'n' +-net user[,vlan=n][,name=str][,hostname=host] + connect the user mode network stack to VLAN 'n' and send + hostname 'host' to DHCP clients +-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile] + connect the host TAP network interface to VLAN 'n' and use the + network scripts 'file' (default=/etc/qemu-ifup) + and 'dfile' (default=/etc/qemu-ifdown); + use '[down]script=no' to disable script execution; + use 'fd=h' to connect to an already opened TAP interface +-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port] + connect the vlan 'n' to another VLAN using a socket connection +-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port] + connect the vlan 'n' to multicast maddr and port +-net none use it alone to have zero network devices; if no -net option + is provided, the default is '-net nic -net user' +-tftp dir allow tftp access to files in dir [-net user] +-bootp file advertise file in BOOTP replies +-smb dir allow SMB access to files in 'dir' [-net user] +-redir [tcp|udp]:host-port:[guest-host]:guest-port + redirect TCP or UDP connections from host to guest [-net user] + +-bt hci,null dumb bluetooth HCI - doesn't respond to commands +-bt hci,host[:id] + use host's HCI with the given name +-bt hci[,vlan=n] + emulate a standard HCI in virtual scatternet 'n' +-bt vhci[,vlan=n] + add host computer to virtual scatternet 'n' using VHCI +-bt device:dev[,vlan=n] + emulate a bluetooth device 'dev' in scatternet 'n' + + +i386 target only: +-win2k-hack use it when installing Windows 2000 to avoid a disk full bug +-rtc-td-hack use it to fix time drift in Windows ACPI HAL +-no-fd-bootchk disable boot signature checking for floppy disks +-no-acpi disable ACPI +-no-hpet disable HPET +-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...] + ACPI table description +Linux boot specific: +-kernel bzImage use 'bzImage' as kernel image +-append cmdline use 'cmdline' as kernel command line +-initrd file use 'file' as initial ram disk + +Debug/Expert options: +-serial dev redirect the serial port to char device 'dev' +-parallel dev redirect the parallel port to char device 'dev' +-monitor dev redirect the monitor to char device 'dev' +-pidfile file write PID to 'file' +-S freeze CPU at startup (use 'c' to start execution) +-s wait gdb connection to port +-p port set gdb connection port [default=1234] +-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) +-hdachs c,h,s[,t] + force hard disk 0 physical geometry and the optional BIOS + translation (t=none or lba) (usually qemu can guess them) +-L path set the directory for the BIOS, VGA BIOS and keymaps +-bios file set the filename for the BIOS +-kernel-kqemu enable KQEMU full virtualization (default is user mode only) +-no-kqemu disable KQEMU kernel module usage +-enable-kvm enable KVM full virtualization support +-no-reboot exit instead of rebooting +-no-shutdown stop before shutdown +-loadvm [tag|id] + start right away with a saved state (loadvm in monitor) +-daemonize daemonize QEMU after initializing +-option-rom rom load a file, rom, into the option ROM space +-clock force the use of the given methods for timer alarm. + To see what timers are available use -clock ? +-localtime set the real time clock to local time [default=utc] +-startdate select initial date of the clock +-icount [N|auto] + enable virtual instruction counter with 2^N clock ticks per instruction +-echr chr set terminal escape character instead of ctrl-a +-virtioconsole c + set virtio console +-show-cursor show cursor +-tb-size n set TB size +-incoming p prepare for incoming migration, listen on port p +-chroot dir Chroot to dir just before starting the VM. +-runas user Change to user id user just before starting the VM. + +During emulation, the following keys are useful: +ctrl-alt-f toggle full screen +ctrl-alt-n switch to virtual console 'n' +ctrl-alt toggle mouse and keyboard grab + +When using -nographic, press 'ctrl-a h' to get some help. diff --git a/tests/qemuhelpdata/qemu-0.9.1 b/tests/qemuhelpdata/qemu-0.9.1 new file mode 100644 index 0000000..0eaeaec --- /dev/null +++ b/tests/qemuhelpdata/qemu-0.9.1 @@ -0,0 +1,102 @@ +QEMU PC emulator version 0.9.1, Copyright (c) 2003-2008 Fabrice Bellard +usage: qemu [options] [disk_image] + +'disk_image' is a raw hard image image for IDE hard disk 0 + +Standard options: +-M machine select emulated machine (-M ? for list) +-cpu cpu select CPU (-cpu ? for list) +-fda/-fdb file use 'file' as floppy disk 0/1 image +-hda/-hdb file use 'file' as IDE hard disk 0/1 image +-hdc/-hdd file use 'file' as IDE hard disk 2/3 image +-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master) +-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][index=i] + [,cyls=c,heads=h,secs=s[,trans=t]][snapshot=on|off] [,cache=on|off] + use 'file' as a drive image +-mtdblock file use 'file' as on-board Flash memory image +-sd file use 'file' as SecureDigital card image +-pflash file use 'file' as a parallel flash image +-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n) +-snapshot write to temporary files instead of disk image files +-no-frame open SDL window without a frame and window decorations +-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt) +-no-quit disable SDL window close capability +-no-fd-bootchk disable boot signature checking for floppy disks +-m megs set virtual RAM size to megs MB [default=128] +-smp n set the number of CPUs to 'n' [default=1] +-nographic disable graphical output and redirect serial I/Os to console +-portrait rotate graphical output 90 deg left (only PXA LCD) +-k language use keyboard layout (for example "fr" for French) +-audio-help print list of audio drivers and their options +-soundhw c1,... enable audio support + and only specified sound cards (comma separated list) + use -soundhw ? to get the list of supported cards + use -soundhw all to enable all of them +-localtime set the real time clock to local time [default=utc] +-full-screen start in full screen +-win2k-hack use it when installing Windows 2000 to avoid a disk full bug +-usb enable the USB driver (will be the default soon) +-usbdevice name add the host or guest USB device 'name' +-name string set the name of the guest + +Network options: +-net nic[,vlan=n][,macaddr=addr][,model=type] + create a new Network Interface Card and connect it to VLAN 'n' +-net user[,vlan=n][,hostname=host] + connect the user mode network stack to VLAN 'n' and send + hostname 'host' to DHCP clients +-net tap[,vlan=n][,fd=h][,ifname=name][,script=file][,downscript=dfile] + connect the host TAP network interface to VLAN 'n' and use the + network scripts 'file' (default=/etc/qemu-ifup) + and 'dfile' (default=/etc/qemu-ifdown); + use '[down]script=no' to disable script execution; + use 'fd=h' to connect to an already opened TAP interface +-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port] + connect the vlan 'n' to another VLAN using a socket connection +-net socket[,vlan=n][,fd=h][,mcast=maddr:port] + connect the vlan 'n' to multicast maddr and port +-net none use it alone to have zero network devices; if no -net option + is provided, the default is '-net nic -net user' + +-tftp dir allow tftp access to files in dir [-net user] +-bootp file advertise file in BOOTP replies +-smb dir allow SMB access to files in 'dir' [-net user] +-redir [tcp|udp]:host-port:[guest-host]:guest-port + redirect TCP or UDP connections from host to guest [-net user] + +Linux boot specific: +-kernel bzImage use 'bzImage' as kernel image +-append cmdline use 'cmdline' as kernel command line +-initrd file use 'file' as initial ram disk + +Debug/Expert options: +-monitor dev redirect the monitor to char device 'dev' +-serial dev redirect the serial port to char device 'dev' +-parallel dev redirect the parallel port to char device 'dev' +-pidfile file Write PID to 'file' +-S freeze CPU at startup (use 'c' to start execution) +-s wait gdb connection to port +-p port set gdb connection port [default=1234] +-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) +-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS + translation (t=none or lba) (usually qemu can guess them) +-L path set the directory for the BIOS, VGA BIOS and keymaps +-kernel-kqemu enable KQEMU full virtualization (default is user mode only) +-no-kqemu disable KQEMU kernel module usage +-std-vga simulate a standard VGA card with VESA Bochs Extensions + (default is CL-GD5446 PCI VGA) +-no-acpi disable ACPI +-no-reboot exit instead of rebooting +-loadvm file start right away with a saved state (loadvm in monitor) +-vnc display start a VNC server on display +-daemonize daemonize QEMU after initializing +-option-rom rom load a file, rom, into the option ROM space +-clock force the use of the given methods for timer alarm. + To see what timers are available use -clock help + +During emulation, the following keys are useful: +ctrl-alt-f toggle full screen +ctrl-alt-n switch to virtual console 'n' +ctrl-alt toggle mouse and keyboard grab + +When using -nographic, press 'ctrl-a h' to get some help. diff --git a/tests/qemuhelpdata/qemu-kvm-0.10.5 b/tests/qemuhelpdata/qemu-kvm-0.10.5 new file mode 100644 index 0000000..29d6f83 --- /dev/null +++ b/tests/qemuhelpdata/qemu-kvm-0.10.5 @@ -0,0 +1,155 @@ +QEMU PC emulator version 0.10.5 (qemu-kvm-0.10.5), Copyright (c) 2003-2008 Fabrice Bellard +usage: qemu [options] [disk_image] + +'disk_image' is a raw hard image image for IDE hard disk 0 + +Standard options: +-h or -help display this help and exit +-M machine select emulated machine (-M ? for list) +-cpu cpu select CPU (-cpu ? for list) +-smp n set the number of CPUs to 'n' [default=1] +-fda/-fdb file use 'file' as floppy disk 0/1 image +-hda/-hdb file use 'file' as IDE hard disk 0/1 image +-hdc/-hdd file use 'file' as IDE hard disk 2/3 image +-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master) +-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i] + [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off] + [,cache=writethrough|writeback|none][,format=f][,serial=s] + [,boot=on|off] + use 'file' as a drive image +-mtdblock file use 'file' as on-board Flash memory image +-sd file use 'file' as SecureDigital card image +-pflash file use 'file' as a parallel flash image +-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n) +-snapshot write to temporary files instead of disk image files +-m megs set virtual RAM size to megs MB [default=128] +-k language use keyboard layout (for example "fr" for French) +-audio-help print list of audio drivers and their options +-soundhw c1,... enable audio support + and only specified sound cards (comma separated list) + use -soundhw ? to get the list of supported cards + use -soundhw all to enable all of them +-usb enable the USB driver (will be the default soon) +-usbdevice name add the host or guest USB device 'name' +-name string set the name of the guest +-uuid %08x-%04x-%04x-%04x-%012x + specify machine UUID + +Display options: +-nographic disable graphical output and redirect serial I/Os to console +-no-frame open SDL window without a frame and window decorations +-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt) +-no-quit disable SDL window close capability +-sdl enable SDL +-portrait rotate graphical output 90 deg left (only PXA LCD) +-vga [std|cirrus|vmware|none] + select video card type +-full-screen start in full screen +-vnc display start a VNC server on display +-name string set the name of the guest +-uuid %08x-%04x-%04x-%04x-%012x specify machine UUID + +Network options: +-net nic[,vlan=n][,macaddr=addr][,model=type][,name=str] + create a new Network Interface Card and connect it to VLAN 'n' +-net user[,vlan=n][,name=str][,hostname=host] + connect the user mode network stack to VLAN 'n' and send + hostname 'host' to DHCP clients +-net tap[,vlan=n][,name=str][,fd=h][,ifname=name][,script=file][,downscript=dfile] + connect the host TAP network interface to VLAN 'n' and use the + network scripts 'file' (default=/etc/qemu-ifup) + and 'dfile' (default=/etc/qemu-ifdown); + use '[down]script=no' to disable script execution; + use 'fd=h' to connect to an already opened TAP interface +-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port] + connect the vlan 'n' to another VLAN using a socket connection +-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port] + connect the vlan 'n' to multicast maddr and port +-net none use it alone to have zero network devices; if no -net option + is provided, the default is '-net nic -net user' +-tftp dir allow tftp access to files in dir [-net user] +-bootp file advertise file in BOOTP replies +-smb dir allow SMB access to files in 'dir' [-net user] +-redir [tcp|udp]:host-port:[guest-host]:guest-port + redirect TCP or UDP connections from host to guest [-net user] + +-bt hci,null dumb bluetooth HCI - doesn't respond to commands +-bt hci,host[:id] + use host's HCI with the given name +-bt hci[,vlan=n] + emulate a standard HCI in virtual scatternet 'n' +-bt vhci[,vlan=n] + add host computer to virtual scatternet 'n' using VHCI +-bt device:dev[,vlan=n] + emulate a bluetooth device 'dev' in scatternet 'n' + + +i386 target only: +-win2k-hack use it when installing Windows 2000 to avoid a disk full bug +-rtc-td-hack use it to fix time drift in Windows ACPI HAL +-no-fd-bootchk disable boot signature checking for floppy disks +-no-acpi disable ACPI +-no-hpet disable HPET +-acpitable [sig=str][,rev=n][,oem_id=str][,oem_table_id=str][,oem_rev=n][,asl_compiler_id=str][,asl_compiler_rev=n][,data=file1[:file2]...] + ACPI table description +Linux boot specific: +-kernel bzImage use 'bzImage' as kernel image +-append cmdline use 'cmdline' as kernel command line +-initrd file use 'file' as initial ram disk + +Debug/Expert options: +-serial dev redirect the serial port to char device 'dev' +-parallel dev redirect the parallel port to char device 'dev' +-monitor dev redirect the monitor to char device 'dev' +-pidfile file write PID to 'file' +-S freeze CPU at startup (use 'c' to start execution) +-s wait gdb connection to port +-p port set gdb connection port [default=1234] +-d item1,... output log to /tmp/qemu.log (use -d ? for a list of log items) +-hdachs c,h,s[,t] + force hard disk 0 physical geometry and the optional BIOS + translation (t=none or lba) (usually qemu can guess them) +-L path set the directory for the BIOS, VGA BIOS and keymaps +-bios file set the filename for the BIOS +-no-kvm disable KVM hardware virtualization +-no-kvm-irqchip disable KVM kernel mode PIC/IOAPIC/LAPIC +-no-kvm-pit disable KVM kernel mode PIT +-no-kvm-pit-reinjection disable KVM kernel mode PIT interrupt reinjection +-enable-nesting enable support for running a VM inside the VM (AMD only) +-pcidevice host=bus:dev.func[,dma=none][,name=string] + expose a PCI device to the guest OS. + dma=none: don't perform any dma translations (default is to use an iommu) + 'string' is used in log output. +-no-reboot exit instead of rebooting +-no-shutdown stop before shutdown +-loadvm [tag|id] + start right away with a saved state (loadvm in monitor) +-daemonize daemonize QEMU after initializing +-tdf inject timer interrupts that got lost +-kvm-shadow-memory megs set the amount of shadow pages to be allocated +-mem-path set the path to hugetlbfs/tmpfs mounted directory, also + enables allocation of guest memory with huge pages +-mem-prealloc toggles preallocation of -mem-path backed physical memory + at startup. Default is enabled. +-option-rom rom load a file, rom, into the option ROM space +-clock force the use of the given methods for timer alarm. + To see what timers are available use -clock ? +-localtime set the real time clock to local time [default=utc] +-startdate select initial date of the clock +-icount [N|auto] + enable virtual instruction counter with 2^N clock ticks per instruction +-echr chr set terminal escape character instead of ctrl-a +-virtioconsole c + set virtio console +-show-cursor show cursor +-tb-size n set TB size +-incoming p prepare for incoming migration, listen on port p +-chroot dir Chroot to dir just before starting the VM. +-runas user Change to user id user just before starting the VM. + +During emulation, the following keys are useful: +ctrl-alt-f toggle full screen +ctrl-alt-n switch to virtual console 'n' +ctrl-alt toggle mouse and keyboard grab + +When using -nographic, press 'ctrl-a h' to get some help. diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c new file mode 100644 index 0000000..836010f --- /dev/null +++ b/tests/qemuhelptest.c @@ -0,0 +1,107 @@ +#include <config.h> + +#ifdef WITH_QEMU + +#include <stdio.h> +#include <stdlib.h> + +#include "testutils.h" +#include "qemu_conf.h" + +#define MAX_HELP_OUTPUT_SIZE 1024*64 + +struct testInfo { + const char *name; + unsigned flags; + unsigned version; + unsigned is_kvm; + unsigned kvm_version; +}; + +static char *progname; +static char *abs_srcdir; + +static int testHelpStrParsing(const void *data) +{ + const struct testInfo *info = data; + char path[PATH_MAX]; + char helpStr[MAX_HELP_OUTPUT_SIZE]; + char *help = &(helpStr[0]); + unsigned flags, version, is_kvm, kvm_version; + + snprintf(path, PATH_MAX, "%s/qemuhelpdata/%s", abs_srcdir, info->name); + + if (virtTestLoadFile(path, &help, MAX_HELP_OUTPUT_SIZE) < 0) + return -1; + + if (qemudParseHelpStr(help, &flags, &version, &is_kvm, &kvm_version) == -1) + return -1; + + if (flags != info->flags) { + fprintf(stderr, "Computed flags do not match: got 0x%x, expected 0x%x\n", + flags, info->flags); + return -1; + } + + if (version != info->version) { + fprintf(stderr, "Parsed versions do not match: got %u, expected %u\n", + version, info->version); + return -1; + } + + if (is_kvm != info->is_kvm) { + fprintf(stderr, "Parsed is_kvm flag does not match: got %u, expected %u\n", + is_kvm, info->is_kvm); + return -1; + } + + if (kvm_version != kvm_version) { + fprintf(stderr, "Parsed KVM versions do not match: got %u, expected %u\n", + version, kvm_version); + return -1; + } + + return 0; +} + +static int +mymain(int argc, char **argv) +{ + int ret = 0; + char cwd[PATH_MAX]; + + progname = argv[0]; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", progname); + return (EXIT_FAILURE); + } + + abs_srcdir = getenv("abs_srcdir"); + if (!abs_srcdir) + abs_srcdir = getcwd(cwd, sizeof(cwd)); + +#define DO_TEST(name, flags, version, is_kvm, kvm_version) \ + do { \ + const struct testInfo info = { name, flags, version, is_kvm, kvm_version }; \ + if (virtTestRun("QEMU Help String Parsing " name, \ + 1, testHelpStrParsing, &info) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST("qemu-0.9.1", 0x002f, 9001, 0, 0); + DO_TEST("kvm-74", 0x233e, 9001, 1, 74); + DO_TEST("qemu-0.10.5", 0x1c6f, 10005, 0, 0); + DO_TEST("qemu-kvm-0.10.5", 0x3d7e, 10005, 1, 0); + DO_TEST("kvm-86", 0x3d7e, 10050, 1, 0); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) + +#else + +int main (void) { return (77); /* means 'test skipped' for automake */ } + +#endif /* WITH_QEMU */ -- 1.6.0.6

On Wed, Jun 10, 2009 at 09:02:41PM +0100, Mark McLoughlin wrote:
diff --git a/tests/Makefile.am b/tests/Makefile.am index 621a0be..3d98d69 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -61,7 +61,7 @@ noinst_PROGRAMS += xml2sexprtest sexpr2xmltest \ reconnect xmconfigtest xencapstest endif if WITH_QEMU -noinst_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest +noinst_PROGRAMS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuhelptest endif
if WITH_SECDRIVER_SELINUX @@ -119,7 +119,7 @@ endif endif
if WITH_QEMU -TESTS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest +TESTS += qemuxml2argvtest qemuxml2xmltest qemuargv2xmltest qemuhelptest endif
The test program is only built if WITH_QEMU is defined, so ...
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c new file mode 100644 index 0000000..836010f --- /dev/null +++ b/tests/qemuhelptest.c @@ -0,0 +1,107 @@ +#include <config.h> + +#ifdef WITH_QEMU
....this source file conditional is redundant.
+ +#include <stdio.h> +#include <stdlib.h> + +#include "testutils.h" +#include "qemu_conf.h" + +#define MAX_HELP_OUTPUT_SIZE 1024*64 + +struct testInfo { + const char *name; + unsigned flags; + unsigned version; + unsigned is_kvm; + unsigned kvm_version; +}; + +static char *progname; +static char *abs_srcdir; + +static int testHelpStrParsing(const void *data) +{ + const struct testInfo *info = data; + char path[PATH_MAX]; + char helpStr[MAX_HELP_OUTPUT_SIZE]; + char *help = &(helpStr[0]); + unsigned flags, version, is_kvm, kvm_version; + + snprintf(path, PATH_MAX, "%s/qemuhelpdata/%s", abs_srcdir, info->name); + + if (virtTestLoadFile(path, &help, MAX_HELP_OUTPUT_SIZE) < 0) + return -1; + + if (qemudParseHelpStr(help, &flags, &version, &is_kvm, &kvm_version) == -1) + return -1; + + if (flags != info->flags) { + fprintf(stderr, "Computed flags do not match: got 0x%x, expected 0x%x\n", + flags, info->flags); + return -1; + } + + if (version != info->version) { + fprintf(stderr, "Parsed versions do not match: got %u, expected %u\n", + version, info->version); + return -1; + } + + if (is_kvm != info->is_kvm) { + fprintf(stderr, "Parsed is_kvm flag does not match: got %u, expected %u\n", + is_kvm, info->is_kvm); + return -1; + } + + if (kvm_version != kvm_version) { + fprintf(stderr, "Parsed KVM versions do not match: got %u, expected %u\n", + version, kvm_version); + return -1; + } + + return 0; +} + +static int +mymain(int argc, char **argv) +{ + int ret = 0; + char cwd[PATH_MAX]; + + progname = argv[0]; + + if (argc > 1) { + fprintf(stderr, "Usage: %s\n", progname); + return (EXIT_FAILURE); + } + + abs_srcdir = getenv("abs_srcdir"); + if (!abs_srcdir) + abs_srcdir = getcwd(cwd, sizeof(cwd)); + +#define DO_TEST(name, flags, version, is_kvm, kvm_version) \ + do { \ + const struct testInfo info = { name, flags, version, is_kvm, kvm_version }; \ + if (virtTestRun("QEMU Help String Parsing " name, \ + 1, testHelpStrParsing, &info) < 0) \ + ret = -1; \ + } while (0) + + DO_TEST("qemu-0.9.1", 0x002f, 9001, 0, 0); + DO_TEST("kvm-74", 0x233e, 9001, 1, 74); + DO_TEST("qemu-0.10.5", 0x1c6f, 10005, 0, 0); + DO_TEST("qemu-kvm-0.10.5", 0x3d7e, 10005, 1, 0); + DO_TEST("kvm-86", 0x3d7e, 10050, 1, 0); + + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIRT_TEST_MAIN(mymain) + +#else + +int main (void) { return (77); /* means 'test skipped' for automake */ } + +#endif /* WITH_QEMU */
And can kill this dummy main() too Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, 2009-06-11 at 14:14 +0100, Daniel P. Berrange wrote: ..
The test program is only built if WITH_QEMU is defined, so ... ... ....this source file conditional is redundant. ... And can kill this dummy main() too
I didn't dream this up myself, you know ... take a look at qemuxml2argvtest :-) Cheers, Mark.

On Thu, Jun 11, 2009 at 02:23:27PM +0100, Mark McLoughlin wrote:
On Thu, 2009-06-11 at 14:14 +0100, Daniel P. Berrange wrote: ..
The test program is only built if WITH_QEMU is defined, so ... ... ....this source file conditional is redundant. ... And can kill this dummy main() too
I didn't dream this up myself, you know ... take a look at qemuxml2argvtest :-)
Also redundant in that existing test file :-) Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, Jun 10, 2009 at 09:02:41PM +0100, Mark McLoughlin wrote:
Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 10 +- src/qemu_conf.h | 6 ++ tests/Makefile.am | 9 ++- tests/qemuhelpdata/kvm-74 | 111 +++++++++++++++++++++++ tests/qemuhelpdata/kvm-86 | 170 ++++++++++++++++++++++++++++++++++++ tests/qemuhelpdata/qemu-0.10.5 | 141 +++++++++++++++++++++++++++++ tests/qemuhelpdata/qemu-0.9.1 | 102 +++++++++++++++++++++ tests/qemuhelpdata/qemu-kvm-0.10.5 | 155 ++++++++++++++++++++++++++++++++ tests/qemuhelptest.c | 107 ++++++++++++++++++++++ 9 files changed, 803 insertions(+), 8 deletions(-) create mode 100644 tests/qemuhelpdata/kvm-74 create mode 100644 tests/qemuhelpdata/kvm-86 create mode 100644 tests/qemuhelpdata/qemu-0.10.5 create mode 100644 tests/qemuhelpdata/qemu-0.9.1 create mode 100644 tests/qemuhelpdata/qemu-kvm-0.10.5 create mode 100644 tests/qemuhelptest.c
very good :-) ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Wed, Jun 10, 2009 at 09:02:40PM +0100, Mark McLoughlin wrote:
The KVM version string can be one of the following:
- qemu-kvm-x.y.z in stable releases - kvm-XX for kvm versions up to kvm-85 - qemu-kvm-devel-XX for kvm version kvm-86 and later
There are only a few of places where we need to detect differences between KVM versions based on 0.9.1:
1) VNET_HDR introduced in kvm-74
2) -incoming tcp introduced in kvm-79
3) -incoming exec introduced in kvm-80
4) -incoming stdio in all earlier kvm versions
With qemu-kvm-0.10.x, we can now assume that (1) is available if it's a KVM release, (2) and (3) is always available and (4) is never available.
So, from now on we should only need to check the qemu version number and the "is_kvm" flag for detecting feature availability. We only need the KVM version number for older releases.
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
ACK, though the 'is_kvm' flag is a little redundant, since it is implied by kvm_version being != 0. Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, 2009-06-11 at 14:12 +0100, Daniel P. Berrange wrote:
ACK, though the 'is_kvm' flag is a little redundant, since it is implied by kvm_version being != 0.
Nope, kvm_version won't be available after kvm-85 unless we start parsing qemu-kvm-devel-86. The reason I didn't do that is that from now on the qemu version and the is_kvm flag is all we should care about. i.e. since the kvm-XX releases are purely development snapshots, if kvm-87 (based on qemu-0.10.50) introduced something new, we'd only support it for qemu >= 0.11.0 and is_kvm == 1. Cheers, Mark.

On Wed, Jun 10, 2009 at 09:02:40PM +0100, Mark McLoughlin wrote:
The KVM version string can be one of the following:
- qemu-kvm-x.y.z in stable releases - kvm-XX for kvm versions up to kvm-85 - qemu-kvm-devel-XX for kvm version kvm-86 and later
Any chance to secure an API in the future from those guys ? But anyway we need to deal with the mess so ...
There are only a few of places where we need to detect differences between KVM versions based on 0.9.1:
1) VNET_HDR introduced in kvm-74
2) -incoming tcp introduced in kvm-79
3) -incoming exec introduced in kvm-80
4) -incoming stdio in all earlier kvm versions
With qemu-kvm-0.10.x, we can now assume that (1) is available if it's a KVM release, (2) and (3) is always available and (4) is never available.
So, from now on we should only need to check the qemu version number and the "is_kvm" flag for detecting feature availability. We only need the KVM version number for older releases.
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
ACK, I don't see a good way to avoid this, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Jun 11, 2009 at 03:53:15PM +0200, Daniel Veillard wrote:
On Wed, Jun 10, 2009 at 09:02:40PM +0100, Mark McLoughlin wrote:
The KVM version string can be one of the following:
- qemu-kvm-x.y.z in stable releases - kvm-XX for kvm versions up to kvm-85 - qemu-kvm-devel-XX for kvm version kvm-86 and later
Any chance to secure an API in the future from those guys ?
But anyway we need to deal with the mess so ...
In 95% of cases we can ignore the version numbers. We aim to detect new command line features from the help output. And for monitor commands we just try them and catch failure. We just needed this version number for a couple of hacks not covered by those two approaches Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Thu, 2009-06-11 at 15:53 +0200, Daniel Veillard wrote:
On Wed, Jun 10, 2009 at 09:02:40PM +0100, Mark McLoughlin wrote:
The KVM version string can be one of the following:
- qemu-kvm-x.y.z in stable releases - kvm-XX for kvm versions up to kvm-85 - qemu-kvm-devel-XX for kvm version kvm-86 and later
Any chance to secure an API in the future from those guys ?
Yeah, I posted a patch to implement an "info capabilities" monitor command a while back, but it didn't end up going anywhere. Committed all the patches now. Cheers, Mark.

On Wed, Jun 10, 2009 at 09:02:39PM +0100, Mark McLoughlin wrote:
This patch is purely re-factoring without any functional changes to make way for the next patch.
The main thing achieved by the refactoring is that we now have easier access to the parenthesised string that KVM folks seem to delight in changing.
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
ACK, this is a nicer separation of work. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Wed, Jun 10, 2009 at 09:02:39PM +0100, Mark McLoughlin wrote:
This patch is purely re-factoring without any functional changes to make way for the next patch.
The main thing achieved by the refactoring is that we now have easier access to the parenthesised string that KVM folks seem to delight in changing.
This kind of parsing looks more flexible to me, even if a bit less readable than using pure sscanf [...]
+#define QEMU_VERSION_STR "QEMU PC emulator version " +#define KVM_VER_PREFIX " (kvm-" + +static int qemudParseHelpStr(const char *help, + unsigned int *flags, + unsigned int *version, + unsigned int *kvm_version) +{ + unsigned major, minor, micro; + const char *p = help; + + *flags = *version = *kvm_version = 0; + + if (!STRPREFIX(p, QEMU_VERSION_STR)) + goto fail; + + p += strlen(QEMU_VERSION_STR);
But I would not integate the spaces in the strings and instead use a macro like #define QEMU_VERSION_STR "QEMU PC emulator version" #define SKIP_BLANKS(p) while ((*(p) == ' ') || (*(p) == '\t')) (p)++; and here do SKIP_BLANKS(p)
+ major = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + minor = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + micro = virParseNumber(&p); + if (major == -1) + goto fail;
and SKIP_BLANKS(p) here and #define KVM_VER_PREFIX "(kvm-" without the leading space.
+ if (STRPREFIX(p, KVM_VER_PREFIX)) { + int ret; + + p += strlen(KVM_VER_PREFIX); + + ret = virParseNumber(&p); + if (ret == -1) + goto fail; + + *kvm_version = ret; [...]
But I'm biased on parsing ... and that's not critical, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, 2009-06-11 at 15:49 +0200, Daniel Veillard wrote:
+#define QEMU_VERSION_STR "QEMU PC emulator version " +#define KVM_VER_PREFIX " (kvm-" + +static int qemudParseHelpStr(const char *help, + unsigned int *flags, + unsigned int *version, + unsigned int *kvm_version) +{ + unsigned major, minor, micro; + const char *p = help; + + *flags = *version = *kvm_version = 0; + + if (!STRPREFIX(p, QEMU_VERSION_STR)) + goto fail; + + p += strlen(QEMU_VERSION_STR);
But I would not integate the spaces in the strings and instead use a macro like #define QEMU_VERSION_STR "QEMU PC emulator version" #define SKIP_BLANKS(p) while ((*(p) == ' ') || (*(p) == '\t')) (p)++;
and here do SKIP_BLANKS(p)
Sounds good, committed the below version. Cheers, Mark. From: Mark McLoughlin <markmc@redhat.com> Subject: [PATCH 1/3] Re-factor qemu version parsing This patch is purely re-factoring without any functional changes to make way for the next patch. The main thing achieved by the refactoring is that we now have easier access to the parenthesised string that KVM folks seem to delight in changing. Signed-off-by: Mark McLoughlin <markmc@redhat.com> --- src/qemu_conf.c | 174 +++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 123 insertions(+), 51 deletions(-) diff --git a/src/qemu_conf.c b/src/qemu_conf.c index 2c1eefc..c8f7f0c 100644 --- a/src/qemu_conf.c +++ b/src/qemu_conf.c @@ -412,54 +412,12 @@ virCapsPtr qemudCapsInit(void) { return NULL; } - -int qemudExtractVersionInfo(const char *qemu, - unsigned int *retversion, - unsigned int *retflags) { - const char *const qemuarg[] = { qemu, "-help", NULL }; - const char *const qemuenv[] = { "LC_ALL=C", NULL }; - pid_t child; - int newstdout = -1; - int ret = -1, status; - unsigned int major, minor, micro; - unsigned int version, kvm_version; +static unsigned int qemudComputeCmdFlags(const char *help, + unsigned int version, + unsigned int kvm_version) +{ unsigned int flags = 0; - if (retflags) - *retflags = 0; - if (retversion) - *retversion = 0; - - if (virExec(NULL, qemuarg, qemuenv, NULL, - &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0) - return -1; - - char *help = NULL; - enum { MAX_HELP_OUTPUT_SIZE = 1024*64 }; - int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help); - if (len < 0) { - virReportSystemError(NULL, errno, "%s", - _("Unable to read QEMU help output")); - goto cleanup2; - } - - if (sscanf(help, "QEMU PC emulator version %u.%u.%u (kvm-%u)", - &major, &minor, µ, &kvm_version) != 4) - kvm_version = 0; - - if (!kvm_version && - sscanf(help, "QEMU PC emulator version %u.%u.%u", - &major, &minor, µ) != 3) { - char *eol = strchr(help, '\n'); - if (eol) *eol = '\0'; - qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("cannot parse QEMU version number in '%s'"), - help); - goto cleanup2; - } - - version = (major * 1000 * 1000) + (minor * 1000) + micro; - if (strstr(help, "-no-kqemu")) flags |= QEMUD_CMD_FLAG_KQEMU; if (strstr(help, "-no-kvm")) @@ -505,6 +463,125 @@ int qemudExtractVersionInfo(const char *qemu, flags |= QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC; } + return flags; +} + +/* We parse the output of 'qemu -help' to get the QEMU + * version number. The first bit is easy, just parse + * 'QEMU PC emulator version x.y.z'. + * + * With qemu-kvm, however, that is followed by a kvm-XX + * string in parenthesis. + */ +#define QEMU_VERSION_STR "QEMU PC emulator version" +#define KVM_VER_PREFIX "(kvm-" + +#define SKIP_BLANKS(p) do { while ((*(p) == ' ') || (*(p) == '\t')) (p)++; } while (0) + +static int qemudParseHelpStr(const char *help, + unsigned int *flags, + unsigned int *version, + unsigned int *kvm_version) +{ + unsigned major, minor, micro; + const char *p = help; + + *flags = *version = *kvm_version = 0; + + if (!STRPREFIX(p, QEMU_VERSION_STR)) + goto fail; + + p += strlen(QEMU_VERSION_STR); + + SKIP_BLANKS(p); + + major = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + minor = virParseNumber(&p); + if (major == -1 || *p != '.') + goto fail; + + ++p; + + micro = virParseNumber(&p); + if (major == -1) + goto fail; + + SKIP_BLANKS(p); + + if (STRPREFIX(p, KVM_VER_PREFIX)) { + int ret; + + p += strlen(KVM_VER_PREFIX); + + ret = virParseNumber(&p); + if (ret == -1) + goto fail; + + *kvm_version = ret; + } + + *version = (major * 1000 * 1000) + (minor * 1000) + micro; + + *flags = qemudComputeCmdFlags(help, *version, *kvm_version); + + qemudDebug("Version %u.%u.%u, cooked version %u, flags %u", + major, minor, micro, *version, *flags); + if (*kvm_version) + qemudDebug("KVM version %u detected", *kvm_version); + + return 0; + +fail: + p = strchr(help, '\n'); + if (p) + p = strndup(help, p - help); + + qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("cannot parse QEMU version number in '%s'"), + p ? p : help); + + VIR_FREE(p); + + return -1; +} + +int qemudExtractVersionInfo(const char *qemu, + unsigned int *retversion, + unsigned int *retflags) { + const char *const qemuarg[] = { qemu, "-help", NULL }; + const char *const qemuenv[] = { "LC_ALL=C", NULL }; + pid_t child; + int newstdout = -1; + int ret = -1, status; + unsigned int version, kvm_version; + unsigned int flags = 0; + + if (retflags) + *retflags = 0; + if (retversion) + *retversion = 0; + + if (virExec(NULL, qemuarg, qemuenv, NULL, + &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0) + return -1; + + char *help = NULL; + enum { MAX_HELP_OUTPUT_SIZE = 1024*64 }; + int len = virFileReadLimFD(newstdout, MAX_HELP_OUTPUT_SIZE, &help); + if (len < 0) { + virReportSystemError(NULL, errno, "%s", + _("Unable to read QEMU help output")); + goto cleanup2; + } + + if (qemudParseHelpStr(help, &version, &kvm_version, &flags) == -1) + goto cleanup2; + if (retversion) *retversion = version; if (retflags) @@ -512,11 +589,6 @@ int qemudExtractVersionInfo(const char *qemu, ret = 0; - qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d", - major, minor, micro, version, flags); - if (kvm_version) - qemudDebug("KVM version %d detected", kvm_version); - cleanup2: VIR_FREE(help); if (close(newstdout) < 0) -- 1.6.0.6
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Mark McLoughlin