Currently we hardcode the QEMU machine types. We should really just
parse the output of 'qemu -M ?' so the lists don't get out of sync.
xenner doesn't support '-M ?', so we still need to hardcode that.
The horrible (const char *const *) is removed in a subsequent patch.
* src/qemu_conf.c: kill the arch_info*machines tables, retain the
hardcoded xenner machine type, add qemudProbeMachineTypes() to
run and parse 'qemu -M ?' and use it in qemudCapsInitGuest()
---
src/qemu_conf.c | 201 ++++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 154 insertions(+), 47 deletions(-)
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 4bd511a..bdbeff2 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -222,31 +222,6 @@ int qemudLoadDriverConfig(struct qemud_driver *driver,
return 0;
}
-/* The list of possible machine types for various architectures,
- as supported by QEMU - taken from 'qemu -M ?' for each arch */
-static const char *const arch_info_hvm_x86_machines[] = {
- "pc", "isapc"
-};
-static const char *const arch_info_hvm_arm_machines[] = {
-
"versatilepb","integratorcp","versatileab","realview",
-
"akita","spitz","borzoi","terrier","sx1-v1","sx1",
-
"cheetah","n800","n810","lm3s811evb","lm3s6965evb",
-
"connex","verdex","mainstone","musicpal","tosa",
-};
-static const char *const arch_info_hvm_mips_machines[] = {
- "mips"
-};
-static const char *const arch_info_hvm_sparc_machines[] = {
- "sun4m"
-};
-static const char *const arch_info_hvm_ppc_machines[] = {
- "g3beige", "mac99", "prep"
-};
-
-static const char *const arch_info_xen_x86_machines[] = {
- "xenner"
-};
-
struct qemu_feature_flags {
const char *name;
const int default_on;
@@ -256,8 +231,7 @@ struct qemu_feature_flags {
struct qemu_arch_info {
const char *arch;
int wordsize;
- const char *const *machines;
- int nmachines;
+ const char *machine;
const char *binary;
const char *altbinary;
const struct qemu_feature_flags *flags;
@@ -279,29 +253,135 @@ static const struct qemu_feature_flags const arch_info_x86_64_flags
[] = {
/* The archicture tables for supported QEMU archs */
static const struct qemu_arch_info const arch_info_hvm[] = {
- { "i686", 32, arch_info_hvm_x86_machines, 2,
- "/usr/bin/qemu", "/usr/bin/qemu-system-x86_64",
arch_info_i686_flags, 4 },
- { "x86_64", 64, arch_info_hvm_x86_machines, 2,
- "/usr/bin/qemu-system-x86_64", NULL, arch_info_x86_64_flags, 2 },
- { "arm", 32, arch_info_hvm_arm_machines, 20,
- "/usr/bin/qemu-system-arm", NULL, NULL, 0 },
- { "mips", 32, arch_info_hvm_mips_machines, 1,
- "/usr/bin/qemu-system-mips", NULL, NULL, 0 },
- { "mipsel", 32, arch_info_hvm_mips_machines, 1,
- "/usr/bin/qemu-system-mipsel", NULL, NULL, 0 },
- { "sparc", 32, arch_info_hvm_sparc_machines, 1,
- "/usr/bin/qemu-system-sparc", NULL, NULL, 0 },
- { "ppc", 32, arch_info_hvm_ppc_machines, 3,
- "/usr/bin/qemu-system-ppc", NULL, NULL, 0 },
+ { "i686", 32, NULL, "/usr/bin/qemu",
+ "/usr/bin/qemu-system-x86_64", arch_info_i686_flags, 4 },
+ { "x86_64", 64, NULL, "/usr/bin/qemu-system-x86_64",
+ NULL, arch_info_x86_64_flags, 2 },
+ { "arm", 32, NULL, "/usr/bin/qemu-system-arm", NULL, NULL,
0 },
+ { "mips", 32, NULL, "/usr/bin/qemu-system-mips", NULL, NULL,
0 },
+ { "mipsel", 32, NULL, "/usr/bin/qemu-system-mipsel", NULL, NULL,
0 },
+ { "sparc", 32, NULL, "/usr/bin/qemu-system-sparc", NULL, NULL,
0 },
+ { "ppc", 32, NULL, "/usr/bin/qemu-system-ppc", NULL, NULL,
0 },
};
static const struct qemu_arch_info const arch_info_xen[] = {
- { "i686", 32, arch_info_xen_x86_machines, 1,
- "/usr/bin/xenner", NULL, arch_info_i686_flags, 4 },
- { "x86_64", 64, arch_info_xen_x86_machines, 1,
- "/usr/bin/xenner", NULL, arch_info_x86_64_flags, 2 },
+ { "i686", 32, "xenner", "/usr/bin/xenner", NULL,
arch_info_i686_flags, 4 },
+ { "x86_64", 64, "xenner", "/usr/bin/xenner", NULL,
arch_info_x86_64_flags, 2 },
};
+
+/* Format is:
+ * <machine> <desc> [(default)]
+ */
+static int
+qemudParseMachineTypesStr(const char *output,
+ char ***machines,
+ int *nmachines)
+{
+ const char *p = output;
+ const char *next;
+ char **list = NULL;
+ int i, nitems = 0;
+
+ do {
+ const char *t;
+ char *machine;
+
+ if ((next = strchr(p, '\n')))
+ ++next;
+
+ if (STRPREFIX(p, "Supported machines are:"))
+ continue;
+
+ if (!(t = strchr(p, ' ')) || (next && t >= next))
+ continue;
+
+ if (!(machine = strndup(p, t - p)))
+ goto error;
+
+ if (VIR_REALLOC_N(list, nitems + 1) < 0) {
+ VIR_FREE(machine);
+ goto error;
+ }
+
+ p = t;
+ if (!(t = strstr(p, "(default)")) || (next && t >= next)) {
+ list[nitems++] = machine;
+ } else {
+ /* put the default first in the list */
+ memmove(list + 1, list, sizeof(*list) * nitems);
+ list[0] = machine;
+ nitems++;
+ }
+ } while ((p = next));
+
+ *machines = list;
+ *nmachines = nitems;
+
+ return 0;
+
+error:
+ for (i = 0; i < nitems; i++)
+ VIR_FREE(list[i]);
+ VIR_FREE(list);
+ return -1;
+}
+
+static int
+qemudProbeMachineTypes(const char *binary,
+ char ***machines,
+ int *nmachines)
+{
+ const char *const qemuarg[] = { binary, "-M", "?", NULL };
+ const char *const qemuenv[] = { "LC_ALL=C", NULL };
+ char *output;
+ enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
+ pid_t child;
+ int newstdout = -1, len;
+ int ret = -1, status;
+
+ if (virExec(NULL, qemuarg, qemuenv, NULL,
+ &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
+ return -1;
+
+ len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &output);
+ if (len < 0) {
+ virReportSystemError(NULL, errno, "%s",
+ _("Unable to read 'qemu -M ?' output"));
+ goto cleanup;
+ }
+
+ if (qemudParseMachineTypesStr(output, machines, nmachines) < 0)
+ goto cleanup2;
+
+ ret = 0;
+
+cleanup2:
+ VIR_FREE(output);
+cleanup:
+ if (close(newstdout) < 0)
+ ret = -1;
+
+rewait:
+ if (waitpid(child, &status, 0) != child) {
+ if (errno == EINTR)
+ goto rewait;
+
+ VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+ WEXITSTATUS(status), (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(status) != 0) {
+ VIR_WARN(_("Unexpected exit status '%d', qemu probably
failed"),
+ WEXITSTATUS(status));
+ }
+
+ return ret;
+}
+
static int
qemudCapsInitGuest(virCapsPtr caps,
const char *hostmachine,
@@ -313,6 +393,8 @@ qemudCapsInitGuest(virCapsPtr caps,
int haskqemu = 0;
const char *kvmbin = NULL;
const char *binary = NULL;
+ char **machines = NULL;
+ int nmachines = 0;
/* Check for existance of base emulator, or alternate base
* which can be used with magic cpu choice
@@ -351,6 +433,23 @@ qemudCapsInitGuest(virCapsPtr caps,
if (!binary)
return 0;
+ if (info->machine) {
+ char *machine;
+
+ if (!(machine = strdup(info->machine)))
+ return -1;
+
+ if (VIR_ALLOC_N(machines, nmachines) < 0) {
+ VIR_FREE(machine);
+ return -1;
+ }
+
+ machines[0] = machine;
+ nmachines = 1;
+
+ } else if (qemudProbeMachineTypes(binary, &machines, &nmachines) < 0)
+ return -1;
+
/* We register kvm as the base emulator too, since we can
* just give -no-kvm to disable acceleration if required */
if ((guest = virCapabilitiesAddGuest(caps,
@@ -359,9 +458,17 @@ qemudCapsInitGuest(virCapsPtr caps,
info->wordsize,
binary,
NULL,
- info->nmachines,
- info->machines)) == NULL)
+ nmachines,
+ (const char *const *)machines)) == NULL) {
+ for (i = 0; i < nmachines; i++)
+ VIR_FREE(machines[i]);
+ VIR_FREE(machines);
return -1;
+ }
+
+ for (i = 0; i < nmachines; i++)
+ VIR_FREE(machines[i]);
+ VIR_FREE(machines);
if (hvm) {
if (virCapabilitiesAddGuestDomain(guest,
--
1.6.2.5