[libvirt] PATCH: Support bootloaders in QEMU driver

The QEMU driver supports booting Xen guests via the Xenner hypervisor. For such paravirtualized guests there is no regular BIOS, so the bootloader has to be run on the host. Xenner defaults to pygrub, but since libvirt has a generic syntax for bootloaders, we should use it. So this patch adds support for the <bootloader> syntax in the QEMU drive, and passes this to Xenner via the -bootloader arg. The patch is overly large, because when we have a bootloader we need to skip the kernel/initrd/cmdline/boot elements & thus caused alot of intrusive code re-indentation . b/tests/qemuxml2argvdata/qemuxml2argv-bootloader.args | 1 b/tests/qemuxml2argvdata/qemuxml2argv-bootloader.xml | 23 + src/qemu_conf.c | 318 +++++++++--------- src/qemu_conf.h | 1 tests/qemuxml2argvtest.c | 1 tests/qemuxml2xmltest.c | 1 6 files changed, 200 insertions(+), 145 deletions(-) Dan. diff -r f6b693192cb2 src/qemu_conf.c --- a/src/qemu_conf.c Mon May 12 09:51:07 2008 -0400 +++ b/src/qemu_conf.c Mon May 12 10:16:21 2008 -0400 @@ -1702,22 +1702,37 @@ xmlXPathFreeObject(obj); + /* Extract bootloader */ + obj = xmlXPathEval(BAD_CAST "string(/domain/bootloader)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + strncpy(def->os.bootloader, (const char*)obj->stringval, sizeof(def->os.bootloader)); + NUL_TERMINATE(def->os.bootloader); + xmlXPathFreeObject(obj); + + /* Set a default OS type, since <type> is optional with bootloader */ + strcpy(def->os.type, "xen"); + } + /* Extract OS type info */ obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + if (!def->os.type[0]) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, + "%s", _("no OS type")); + goto error; + } + } else { + strcpy(def->os.type, (const char *)obj->stringval); + xmlXPathFreeObject(obj); + } + + if (!virCapabilitiesSupportsGuestOSType(driver->caps, def->os.type)) { qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, - "%s", _("no OS type")); - goto error; - } - if (!virCapabilitiesSupportsGuestOSType(driver->caps, (const char*)obj->stringval)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, - "%s", obj->stringval); - goto error; - } - strcpy(def->os.type, (const char *)obj->stringval); - xmlXPathFreeObject(obj); - + "%s", def->os.type); + goto error; + } obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1]/@arch)", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || @@ -1772,75 +1787,76 @@ xmlXPathFreeObject(obj); - obj = xmlXPathEval(BAD_CAST "string(/domain/os/kernel[1])", ctxt); - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("kernel path too long")); - goto error; - } - strcpy(def->os.kernel, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - - obj = xmlXPathEval(BAD_CAST "string(/domain/os/initrd[1])", ctxt); - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("initrd path too long")); - goto error; - } - strcpy(def->os.initrd, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - - obj = xmlXPathEval(BAD_CAST "string(/domain/os/cmdline[1])", ctxt); - if ((obj != NULL) && (obj->type == XPATH_STRING) && - (obj->stringval != NULL) && (obj->stringval[0] != 0)) { - if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - "%s", _("cmdline arguments too long")); - goto error; - } - strcpy(def->os.cmdline, (const char *)obj->stringval); - } - xmlXPathFreeObject(obj); - - - /* analysis of the disk devices */ - obj = xmlXPathEval(BAD_CAST "/domain/os/boot", ctxt); - if ((obj != NULL) && (obj->type == XPATH_NODESET) && - (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { - for (i = 0; i < obj->nodesetval->nodeNr && i < QEMUD_MAX_BOOT_DEVS ; i++) { - if (!(prop = xmlGetProp(obj->nodesetval->nodeTab[i], BAD_CAST "dev"))) - continue; - if (STREQ((char *)prop, "hd")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_DISK; - } else if (STREQ((char *)prop, "fd")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_FLOPPY; - } else if (STREQ((char *)prop, "cdrom")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_CDROM; - } else if (STREQ((char *)prop, "network")) { - def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_NET; - } else { - qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, - _("unknown boot device \'%s\'"), (char*)prop); - goto error; - } - xmlFree(prop); - prop = NULL; - } - } - xmlXPathFreeObject(obj); - if (def->os.nBootDevs == 0) { - def->os.nBootDevs = 1; - def->os.bootDevs[0] = QEMUD_BOOT_DISK; - } - + if (!def->os.bootloader[0]) { + obj = xmlXPathEval(BAD_CAST "string(/domain/os/kernel[1])", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("kernel path too long")); + goto error; + } + strcpy(def->os.kernel, (const char *)obj->stringval); + } + xmlXPathFreeObject(obj); + + + obj = xmlXPathEval(BAD_CAST "string(/domain/os/initrd[1])", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("initrd path too long")); + goto error; + } + strcpy(def->os.initrd, (const char *)obj->stringval); + } + xmlXPathFreeObject(obj); + + + obj = xmlXPathEval(BAD_CAST "string(/domain/os/cmdline[1])", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + if (strlen((const char *)obj->stringval) >= (PATH_MAX-1)) { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + "%s", _("cmdline arguments too long")); + goto error; + } + strcpy(def->os.cmdline, (const char *)obj->stringval); + } + xmlXPathFreeObject(obj); + + + /* analysis of the disk devices */ + obj = xmlXPathEval(BAD_CAST "/domain/os/boot", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { + for (i = 0; i < obj->nodesetval->nodeNr && i < QEMUD_MAX_BOOT_DEVS ; i++) { + if (!(prop = xmlGetProp(obj->nodesetval->nodeTab[i], BAD_CAST "dev"))) + continue; + if (STREQ((char *)prop, "hd")) { + def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_DISK; + } else if (STREQ((char *)prop, "fd")) { + def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_FLOPPY; + } else if (STREQ((char *)prop, "cdrom")) { + def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_CDROM; + } else if (STREQ((char *)prop, "network")) { + def->os.bootDevs[def->os.nBootDevs++] = QEMUD_BOOT_NET; + } else { + qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR, + _("unknown boot device \'%s\'"), (char*)prop); + goto error; + } + xmlFree(prop); + prop = NULL; + } + } + xmlXPathFreeObject(obj); + if (def->os.nBootDevs == 0) { + def->os.nBootDevs = 1; + def->os.bootDevs[0] = QEMUD_BOOT_DISK; + } + } obj = xmlXPathEval(BAD_CAST "string(/domain/devices/emulator[1])", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || @@ -2371,6 +2387,7 @@ (vm->def->os.kernel[0] ? 2 : 0) + /* kernel */ (vm->def->os.initrd[0] ? 2 : 0) + /* initrd */ (vm->def->os.cmdline[0] ? 2 : 0) + /* cmdline */ + (vm->def->os.bootloader[0] ? 2 : 0) + /* bootloader */ (vm->def->graphicsType == QEMUD_GRAPHICS_VNC ? 2 : (vm->def->graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)) + /* graphics */ (vm->migrateFrom[0] ? 3 : 0); /* migrateFrom */ @@ -2438,47 +2455,54 @@ goto no_memory; } - for (i = 0 ; i < vm->def->os.nBootDevs ; i++) { - switch (vm->def->os.bootDevs[i]) { - case QEMUD_BOOT_CDROM: - boot[i] = 'd'; - break; - case QEMUD_BOOT_FLOPPY: - boot[i] = 'a'; - break; - case QEMUD_BOOT_DISK: - boot[i] = 'c'; - break; - case QEMUD_BOOT_NET: - boot[i] = 'n'; - break; - default: - boot[i] = 'c'; - break; - } - } - boot[vm->def->os.nBootDevs] = '\0'; - if (!((*argv)[++n] = strdup("-boot"))) - goto no_memory; - if (!((*argv)[++n] = strdup(boot))) - goto no_memory; - - if (vm->def->os.kernel[0]) { - if (!((*argv)[++n] = strdup("-kernel"))) - goto no_memory; - if (!((*argv)[++n] = strdup(vm->def->os.kernel))) - goto no_memory; - } - if (vm->def->os.initrd[0]) { - if (!((*argv)[++n] = strdup("-initrd"))) - goto no_memory; - if (!((*argv)[++n] = strdup(vm->def->os.initrd))) - goto no_memory; - } - if (vm->def->os.cmdline[0]) { - if (!((*argv)[++n] = strdup("-append"))) - goto no_memory; - if (!((*argv)[++n] = strdup(vm->def->os.cmdline))) + if (!vm->def->os.bootloader[0]) { + for (i = 0 ; i < vm->def->os.nBootDevs ; i++) { + switch (vm->def->os.bootDevs[i]) { + case QEMUD_BOOT_CDROM: + boot[i] = 'd'; + break; + case QEMUD_BOOT_FLOPPY: + boot[i] = 'a'; + break; + case QEMUD_BOOT_DISK: + boot[i] = 'c'; + break; + case QEMUD_BOOT_NET: + boot[i] = 'n'; + break; + default: + boot[i] = 'c'; + break; + } + } + boot[vm->def->os.nBootDevs] = '\0'; + if (!((*argv)[++n] = strdup("-boot"))) + goto no_memory; + if (!((*argv)[++n] = strdup(boot))) + goto no_memory; + + if (vm->def->os.kernel[0]) { + if (!((*argv)[++n] = strdup("-kernel"))) + goto no_memory; + if (!((*argv)[++n] = strdup(vm->def->os.kernel))) + goto no_memory; + } + if (vm->def->os.initrd[0]) { + if (!((*argv)[++n] = strdup("-initrd"))) + goto no_memory; + if (!((*argv)[++n] = strdup(vm->def->os.initrd))) + goto no_memory; + } + if (vm->def->os.cmdline[0]) { + if (!((*argv)[++n] = strdup("-append"))) + goto no_memory; + if (!((*argv)[++n] = strdup(vm->def->os.cmdline))) + goto no_memory; + } + } else { + if (!((*argv)[++n] = strdup("-bootloader"))) + goto no_memory; + if (!((*argv)[++n] = strdup(vm->def->os.bootloader))) goto no_memory; } @@ -3809,6 +3833,8 @@ virBufferVSprintf(&buf, " <memory>%lu</memory>\n", def->maxmem); virBufferVSprintf(&buf, " <currentMemory>%lu</currentMemory>\n", def->memory); virBufferVSprintf(&buf, " <vcpu>%d</vcpu>\n", def->vcpus); + if (def->os.bootloader[0]) + virBufferVSprintf(&buf, " <bootloader>%s</bootloader>\n", def->os.bootloader); virBufferAddLit(&buf, " <os>\n"); if (def->virtType == QEMUD_VIRT_QEMU) @@ -3817,30 +3843,32 @@ else virBufferVSprintf(&buf, " <type>%s</type>\n", def->os.type); - if (def->os.kernel[0]) - virBufferVSprintf(&buf, " <kernel>%s</kernel>\n", def->os.kernel); - if (def->os.initrd[0]) - virBufferVSprintf(&buf, " <initrd>%s</initrd>\n", def->os.initrd); - if (def->os.cmdline[0]) - virBufferVSprintf(&buf, " <cmdline>%s</cmdline>\n", def->os.cmdline); - - for (n = 0 ; n < def->os.nBootDevs ; n++) { - const char *boottype = "hd"; - switch (def->os.bootDevs[n]) { - case QEMUD_BOOT_FLOPPY: - boottype = "fd"; - break; - case QEMUD_BOOT_DISK: - boottype = "hd"; - break; - case QEMUD_BOOT_CDROM: - boottype = "cdrom"; - break; - case QEMUD_BOOT_NET: - boottype = "network"; - break; - } - virBufferVSprintf(&buf, " <boot dev='%s'/>\n", boottype); + if (!def->os.bootloader[0]) { + if (def->os.kernel[0]) + virBufferVSprintf(&buf, " <kernel>%s</kernel>\n", def->os.kernel); + if (def->os.initrd[0]) + virBufferVSprintf(&buf, " <initrd>%s</initrd>\n", def->os.initrd); + if (def->os.cmdline[0]) + virBufferVSprintf(&buf, " <cmdline>%s</cmdline>\n", def->os.cmdline); + + for (n = 0 ; n < def->os.nBootDevs ; n++) { + const char *boottype = "hd"; + switch (def->os.bootDevs[n]) { + case QEMUD_BOOT_FLOPPY: + boottype = "fd"; + break; + case QEMUD_BOOT_DISK: + boottype = "hd"; + break; + case QEMUD_BOOT_CDROM: + boottype = "cdrom"; + break; + case QEMUD_BOOT_NET: + boottype = "network"; + break; + } + virBufferVSprintf(&buf, " <boot dev='%s'/>\n", boottype); + } } virBufferAddLit(&buf, " </os>\n"); diff -r f6b693192cb2 src/qemu_conf.h --- a/src/qemu_conf.h Mon May 12 09:51:07 2008 -0400 +++ b/src/qemu_conf.h Mon May 12 10:16:21 2008 -0400 @@ -270,6 +270,7 @@ char initrd[PATH_MAX]; char cmdline[PATH_MAX]; char binary[PATH_MAX]; + char bootloader[PATH_MAX]; }; /* Guest VM main configuration */ diff -r f6b693192cb2 tests/qemuxml2argvdata/qemuxml2argv-bootloader.args --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/qemuxml2argvdata/qemuxml2argv-bootloader.args Mon May 12 10:16:21 2008 -0400 @@ -0,0 +1,1 @@ +/usr/bin/qemu-kvm -M xenner -m 214 -smp 1 -nographic -monitor pty -no-acpi -bootloader /usr/bin/pygrub -cdrom /dev/cdrom -net none -serial none -parallel none -usb \ No newline at end of file diff -r f6b693192cb2 tests/qemuxml2argvdata/qemuxml2argv-bootloader.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/qemuxml2argvdata/qemuxml2argv-bootloader.xml Mon May 12 10:16:21 2008 -0400 @@ -0,0 +1,23 @@ +<domain type='kvm'> + <name>QEMUGuest1</name> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> + <memory>219200</memory> + <currentMemory>219200</currentMemory> + <vcpu>1</vcpu> + <bootloader>/usr/bin/pygrub</bootloader> + <os> + <type>xen</type> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-kvm</emulator> + <disk type='block' device='cdrom'> + <source dev='/dev/cdrom'/> + <target dev='hdc' bus='ide'/> + <readonly/> + </disk> + </devices> +</domain> diff -r f6b693192cb2 tests/qemuxml2argvtest.c --- a/tests/qemuxml2argvtest.c Mon May 12 09:51:07 2008 -0400 +++ b/tests/qemuxml2argvtest.c Mon May 12 10:16:21 2008 -0400 @@ -144,6 +144,7 @@ DO_TEST("boot-cdrom", 0); DO_TEST("boot-network", 0); DO_TEST("boot-floppy", 0); + DO_TEST("bootloader", 0); DO_TEST("clock-utc", 0); DO_TEST("clock-localtime", 0); DO_TEST("disk-cdrom", 0); diff -r f6b693192cb2 tests/qemuxml2xmltest.c --- a/tests/qemuxml2xmltest.c Mon May 12 09:51:07 2008 -0400 +++ b/tests/qemuxml2xmltest.c Mon May 12 10:16:21 2008 -0400 @@ -97,6 +97,7 @@ DO_TEST("boot-cdrom"); DO_TEST("boot-network"); DO_TEST("boot-floppy"); + DO_TEST("bootloader"); DO_TEST("clock-utc"); DO_TEST("clock-localtime"); DO_TEST("disk-cdrom"); -- |: Red Hat, Engineering, Boston -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 :|

"Daniel P. Berrange" <berrange@redhat.com> wrote:
The QEMU driver supports booting Xen guests via the Xenner hypervisor. For such paravirtualized guests there is no regular BIOS, so the bootloader has to be run on the host. Xenner defaults to pygrub, but since libvirt has a generic syntax for bootloaders, we should use it. So this patch adds support for the <bootloader> syntax in the QEMU drive, and passes this to Xenner via the -bootloader arg.
The patch is overly large, because when we have a bootloader we need to skip the kernel/initrd/cmdline/boot elements & thus caused alot of intrusive code re-indentation .
Hmm... that patch didn't apply to latest. But only the big indentation-changing hunk failed, and it was one new line and the rest just white-space diffs, so no problem. and even if it hadn't, "git diff -w" makes it easy to see only the essential changes. ACK.

On Tue, May 13, 2008 at 09:07:45AM +0200, Jim Meyering wrote:
"Daniel P. Berrange" <berrange@redhat.com> wrote:
The QEMU driver supports booting Xen guests via the Xenner hypervisor. For such paravirtualized guests there is no regular BIOS, so the bootloader has to be run on the host. Xenner defaults to pygrub, but since libvirt has a generic syntax for bootloaders, we should use it. So this patch adds support for the <bootloader> syntax in the QEMU drive, and passes this to Xenner via the -bootloader arg.
The patch is overly large, because when we have a bootloader we need to skip the kernel/initrd/cmdline/boot elements & thus caused alot of intrusive code re-indentation .
Hmm... that patch didn't apply to latest. But only the big indentation-changing hunk failed, and it was one new line and the rest just white-space diffs, so no problem. and even if it hadn't, "git diff -w" makes it easy to see only the essential changes.
Sorry, I should have made it clearer that the set of patches apply in series, and are dependant on the STREQ patch too. The ordering was: strcmp-cleanup xen-disk-bus xen-input-bus qemu-name-arg xen-bootloader kvm-vcpus default-bus Regards, Dan. -- |: Red Hat, Engineering, Boston -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 Tue, May 13, 2008 at 12:31:36AM +0100, Daniel P. Berrange wrote:
The QEMU driver supports booting Xen guests via the Xenner hypervisor. For such paravirtualized guests there is no regular BIOS, so the bootloader has to be run on the host. Xenner defaults to pygrub, but since libvirt has a generic syntax for bootloaders, we should use it. So this patch adds support for the <bootloader> syntax in the QEMU drive, and passes this to Xenner via the -bootloader arg.
The patch is overly large, because when we have a bootloader we need to skip the kernel/initrd/cmdline/boot elements & thus caused alot of intrusive code re-indentation . [...]
+ /* Extract bootloader */ + obj = xmlXPathEval(BAD_CAST "string(/domain/bootloader)", ctxt); + if ((obj != NULL) && (obj->type == XPATH_STRING) && + (obj->stringval != NULL) && (obj->stringval[0] != 0)) { + strncpy(def->os.bootloader, (const char*)obj->stringval, sizeof(def->os.bootloader)); + NUL_TERMINATE(def->os.bootloader); + xmlXPathFreeObject(obj); + + /* Set a default OS type, since <type> is optional with bootloader */ + strcpy(def->os.type, "xen"); + } + /* Extract OS type info */ obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + if (!def->os.type[0]) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, + "%s", _("no OS type")); + goto error; + } + } else { + strcpy(def->os.type, (const char *)obj->stringval); + xmlXPathFreeObject(obj); + }
Argh, that part of the code has not been cleaned up, using virXPathString there would make this way easier to read and check. The big indentation block change inflated the patch size a bit. it still look fine. Daniel -- Red Hat Virtualization group http://redhat.com/virtualization/ Daniel Veillard | virtualization library http://libvirt.org/ veillard@redhat.com | libxml GNOME XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | Rpmfind RPM search engine http://rpmfind.net/

On Thu, May 15, 2008 at 11:09:13AM -0400, Daniel Veillard wrote:
On Tue, May 13, 2008 at 12:31:36AM +0100, Daniel P. Berrange wrote:
The QEMU driver supports booting Xen guests via the Xenner hypervisor. For such paravirtualized guests there is no regular BIOS, so the bootloader has to be run on the host. Xenner defaults to pygrub, but since libvirt has a generic syntax for bootloaders, we should use it. So this patch adds support for the <bootloader> syntax in the QEMU drive, and passes this to Xenner via the -bootloader arg.
The patch is overly large, because when we have a bootloader we need to skip the kernel/initrd/cmdline/boot elements & thus caused alot of intrusive code re-indentation . [...]
/* Extract OS type info */ obj = xmlXPathEval(BAD_CAST "string(/domain/os/type[1])", ctxt); if ((obj == NULL) || (obj->type != XPATH_STRING) || (obj->stringval == NULL) || (obj->stringval[0] == 0)) { + if (!def->os.type[0]) { + qemudReportError(conn, NULL, NULL, VIR_ERR_OS_TYPE, + "%s", _("no OS type")); + goto error; + } + } else { + strcpy(def->os.type, (const char *)obj->stringval); + xmlXPathFreeObject(obj); + }
Argh, that part of the code has not been cleaned up, using virXPathString there would make this way easier to read and check.
Yes, that's something that needs to be sorted out.
The big indentation block change inflated the patch size a bit. it still look fine.
This is applied too now. Regards, Dan -- |: Red Hat, Engineering, Boston -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 :|
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Jim Meyering