2008-05-22 16:18:40 +00:00
|
|
|
#include <config.h>
|
2008-06-26 09:37:51 +00:00
|
|
|
#ifdef WITH_QEMU
|
2008-05-16 16:51:30 +00:00
|
|
|
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "testutilsqemu.h"
|
2017-07-21 12:24:51 +00:00
|
|
|
# include "testutilshostcpus.h"
|
2010-03-09 18:22:22 +00:00
|
|
|
# include "testutils.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
# include "viralloc.h"
|
2010-04-16 06:01:59 +00:00
|
|
|
# include "cpu_conf.h"
|
2010-04-20 21:22:49 +00:00
|
|
|
# include "qemu/qemu_driver.h"
|
2010-12-17 16:41:51 +00:00
|
|
|
# include "qemu/qemu_domain.h"
|
2017-03-22 15:22:15 +00:00
|
|
|
# define __QEMU_CAPSPRIV_H_ALLOW__
|
2015-09-09 14:03:14 +00:00
|
|
|
# include "qemu/qemu_capspriv.h"
|
2013-05-03 12:52:21 +00:00
|
|
|
# include "virstring.h"
|
2017-07-19 15:01:56 +00:00
|
|
|
# include "virfilecache.h"
|
2013-05-03 12:52:21 +00:00
|
|
|
|
|
|
|
# define VIR_FROM_THIS VIR_FROM_QEMU
|
2008-05-16 16:51:30 +00:00
|
|
|
|
2015-03-23 16:19:28 +00:00
|
|
|
virCPUDefPtr cpuDefault;
|
|
|
|
virCPUDefPtr cpuHaswell;
|
2016-09-13 20:27:09 +00:00
|
|
|
virCPUDefPtr cpuPower8;
|
2017-05-17 14:39:16 +00:00
|
|
|
virCPUDefPtr cpuPower9;
|
2015-03-23 16:19:28 +00:00
|
|
|
|
2016-12-20 09:10:05 +00:00
|
|
|
typedef enum {
|
2017-04-06 16:33:52 +00:00
|
|
|
TEST_UTILS_QEMU_BIN_I686,
|
|
|
|
TEST_UTILS_QEMU_BIN_X86_64,
|
|
|
|
TEST_UTILS_QEMU_BIN_AARCH64,
|
|
|
|
TEST_UTILS_QEMU_BIN_ARM,
|
|
|
|
TEST_UTILS_QEMU_BIN_PPC64,
|
|
|
|
TEST_UTILS_QEMU_BIN_PPC,
|
2018-08-22 09:15:27 +00:00
|
|
|
TEST_UTILS_QEMU_BIN_RISCV32,
|
|
|
|
TEST_UTILS_QEMU_BIN_RISCV64,
|
2017-04-06 16:33:52 +00:00
|
|
|
TEST_UTILS_QEMU_BIN_S390X
|
2016-12-20 09:10:05 +00:00
|
|
|
} QEMUBinType;
|
|
|
|
|
|
|
|
static const char *QEMUBinList[] = {
|
2017-04-06 16:33:52 +00:00
|
|
|
"/usr/bin/qemu-system-i686",
|
2016-12-20 09:10:05 +00:00
|
|
|
"/usr/bin/qemu-system-x86_64",
|
|
|
|
"/usr/bin/qemu-system-aarch64",
|
|
|
|
"/usr/bin/qemu-system-arm",
|
|
|
|
"/usr/bin/qemu-system-ppc64",
|
|
|
|
"/usr/bin/qemu-system-ppc",
|
2018-08-22 09:15:27 +00:00
|
|
|
"/usr/bin/qemu-system-riscv32",
|
|
|
|
"/usr/bin/qemu-system-riscv64",
|
2016-12-20 09:10:05 +00:00
|
|
|
"/usr/bin/qemu-system-s390x"
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2009-09-10 09:16:27 +00:00
|
|
|
static virCapsGuestMachinePtr *testQemuAllocMachines(int *nmachines)
|
|
|
|
{
|
|
|
|
virCapsGuestMachinePtr *machines;
|
|
|
|
static const char *const x86_machines[] = {
|
|
|
|
"pc", "isapc"
|
|
|
|
};
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(x86_machines,
|
|
|
|
ARRAY_CARDINALITY(x86_machines));
|
|
|
|
if (machines == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
*nmachines = ARRAY_CARDINALITY(x86_machines);
|
|
|
|
|
|
|
|
return machines;
|
|
|
|
}
|
|
|
|
|
2009-09-10 10:19:12 +00:00
|
|
|
/* Newer versions of qemu have versioned machine types to allow
|
|
|
|
* compatibility with older releases.
|
|
|
|
* The 'pc' machine type is an alias of the newest machine type.
|
|
|
|
*/
|
|
|
|
static virCapsGuestMachinePtr *testQemuAllocNewerMachines(int *nmachines)
|
|
|
|
{
|
|
|
|
virCapsGuestMachinePtr *machines;
|
|
|
|
char *canonical;
|
|
|
|
static const char *const x86_machines[] = {
|
|
|
|
"pc-0.11", "pc", "pc-0.10", "isapc"
|
|
|
|
};
|
|
|
|
|
2013-05-03 12:52:21 +00:00
|
|
|
if (VIR_STRDUP(canonical, x86_machines[0]) < 0)
|
2009-09-10 10:19:12 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(x86_machines,
|
|
|
|
ARRAY_CARDINALITY(x86_machines));
|
|
|
|
if (machines == NULL) {
|
|
|
|
VIR_FREE(canonical);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
machines[1]->canonical = canonical;
|
|
|
|
|
|
|
|
*nmachines = ARRAY_CARDINALITY(x86_machines);
|
|
|
|
|
|
|
|
return machines;
|
|
|
|
}
|
|
|
|
|
Fix default console type setting
The default console type may vary based on the OS type. ie a Xen
paravirt guests wants a 'xen' console, while a fullvirt guests
wants a 'serial' console.
A plain integer default console type in the capabilities does
not suffice. Instead introduce a callback that is passed the
OS type.
* src/conf/capabilities.h: Use a callback for default console
type
* src/conf/domain_conf.c, src/conf/domain_conf.h: Use callback
for default console type. Add missing LXC/OpenVZ console types.
* src/esx/esx_driver.c, src/libxl/libxl_conf.c,
src/lxc/lxc_conf.c, src/openvz/openvz_conf.c,
src/phyp/phyp_driver.c, src/qemu/qemu_capabilities.c,
src/uml/uml_conf.c, src/vbox/vbox_tmpl.c,
src/vmware/vmware_conf.c, src/xen/xen_hypervisor.c,
src/xenapi/xenapi_driver.c: Set default console type callback
2011-10-20 13:56:20 +00:00
|
|
|
|
2016-12-19 22:52:33 +00:00
|
|
|
static int
|
|
|
|
testQemuAddI686Guest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
int nmachines = 0;
|
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
if (!(machines = testQemuAllocMachines(&nmachines)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(guest = virCapabilitiesAddGuest(caps,
|
|
|
|
VIR_DOMAIN_OSTYPE_HVM,
|
|
|
|
VIR_ARCH_I686,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_I686],
|
2016-12-19 22:52:33 +00:00
|
|
|
NULL,
|
|
|
|
nmachines,
|
|
|
|
machines)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestFeature(guest, "cpuselection", true, false))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
machines = NULL;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestDomain(guest,
|
|
|
|
VIR_DOMAIN_VIRT_QEMU,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(machines = testQemuAllocMachines(&nmachines)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestDomain(guest,
|
|
|
|
VIR_DOMAIN_VIRT_KVM,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_I686],
|
2016-12-19 22:52:33 +00:00
|
|
|
NULL,
|
|
|
|
nmachines,
|
|
|
|
machines))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virCapabilitiesFreeMachines(machines, nmachines);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
testQemuAddX86_64Guest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
int nmachines = 0;
|
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
if (!(machines = testQemuAllocNewerMachines(&nmachines)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(guest = virCapabilitiesAddGuest(caps,
|
|
|
|
VIR_DOMAIN_OSTYPE_HVM,
|
|
|
|
VIR_ARCH_X86_64,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_X86_64],
|
2016-12-19 22:52:33 +00:00
|
|
|
NULL,
|
|
|
|
nmachines,
|
|
|
|
machines)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestFeature(guest, "cpuselection", true, false))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
machines = NULL;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestDomain(guest,
|
|
|
|
VIR_DOMAIN_VIRT_QEMU,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(machines = testQemuAllocMachines(&nmachines)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestDomain(guest,
|
|
|
|
VIR_DOMAIN_VIRT_KVM,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_X86_64],
|
2016-12-19 22:52:33 +00:00
|
|
|
NULL,
|
|
|
|
nmachines,
|
|
|
|
machines))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
machines = NULL;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestDomain(guest,
|
|
|
|
VIR_DOMAIN_VIRT_KVM,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_X86_64],
|
2016-12-19 22:52:33 +00:00
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virCapabilitiesFreeMachines(machines, nmachines);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-12-12 23:39:33 +00:00
|
|
|
static int testQemuAddPPC64Guest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
static const char *machine[] = { "pseries" };
|
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(machine, 1);
|
|
|
|
if (!machines)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:09:16 +00:00
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_PPC64,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_PPC64],
|
2016-12-20 09:10:05 +00:00
|
|
|
NULL, 1, machines);
|
2011-12-12 23:39:33 +00:00
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:38:10 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
2011-12-12 23:39:33 +00:00
|
|
|
goto error;
|
2017-06-29 12:49:33 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
|
|
|
|
NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
2011-12-12 23:39:33 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
error:
|
2011-12-12 23:39:33 +00:00
|
|
|
/* No way to free a guest? */
|
|
|
|
virCapabilitiesFreeMachines(machines, 1);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-02-26 17:15:54 +00:00
|
|
|
static int testQemuAddPPC64LEGuest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
static const char *machine[] = { "pseries" };
|
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(machine, 1);
|
|
|
|
if (!machines)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:09:16 +00:00
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_PPC64LE,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_PPC64],
|
2016-12-20 09:10:05 +00:00
|
|
|
NULL, 1, machines);
|
2015-02-26 17:15:54 +00:00
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:38:10 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
2015-02-26 17:15:54 +00:00
|
|
|
goto error;
|
2017-06-29 12:49:33 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
|
|
|
|
NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
2015-02-26 17:15:54 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
/* No way to free a guest? */
|
|
|
|
virCapabilitiesFreeMachines(machines, 1);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-03-14 04:49:43 +00:00
|
|
|
static int testQemuAddPPCGuest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
static const char *machine[] = { "g3beige",
|
|
|
|
"mac99",
|
|
|
|
"prep",
|
2014-05-27 05:44:13 +00:00
|
|
|
"ppce500" };
|
2013-03-14 04:49:43 +00:00
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(machine, 1);
|
|
|
|
if (!machines)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:09:16 +00:00
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_PPC,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_PPC],
|
2016-12-20 09:10:05 +00:00
|
|
|
NULL, 1, machines);
|
2013-03-14 04:49:43 +00:00
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:38:10 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
2013-03-14 04:49:43 +00:00
|
|
|
goto error;
|
2017-06-29 12:49:33 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
|
|
|
|
NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
2013-03-14 04:49:43 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
error:
|
2013-03-14 04:49:43 +00:00
|
|
|
/* No way to free a guest? */
|
|
|
|
virCapabilitiesFreeMachines(machines, 1);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-08-22 09:15:27 +00:00
|
|
|
static int testQemuAddRISCV32Guest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
static const char *names[] = { "spike_v1.10",
|
|
|
|
"spike_v1.9.1",
|
|
|
|
"sifive_e",
|
|
|
|
"virt",
|
|
|
|
"sifive_u" };
|
|
|
|
static const int nmachines = ARRAY_CARDINALITY(names);
|
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(names, nmachines);
|
|
|
|
if (!machines)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_RISCV32,
|
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_RISCV32],
|
|
|
|
NULL, nmachines, machines);
|
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virCapabilitiesFreeMachines(machines, nmachines);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int testQemuAddRISCV64Guest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
static const char *names[] = { "spike_v1.10",
|
|
|
|
"spike_v1.9.1",
|
|
|
|
"sifive_e",
|
|
|
|
"virt",
|
|
|
|
"sifive_u" };
|
|
|
|
static const int nmachines = ARRAY_CARDINALITY(names);
|
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(names, nmachines);
|
|
|
|
if (!machines)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_RISCV64,
|
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_RISCV64],
|
|
|
|
NULL, nmachines, machines);
|
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virCapabilitiesFreeMachines(machines, nmachines);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-06-29 15:02:07 +00:00
|
|
|
static int testQemuAddS390Guest(virCapsPtr caps)
|
|
|
|
{
|
2013-03-05 15:44:23 +00:00
|
|
|
static const char *s390_machines[] = { "s390-virtio",
|
|
|
|
"s390-ccw-virtio" };
|
2012-06-29 15:02:07 +00:00
|
|
|
virCapsGuestMachinePtr *machines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
machines = virCapabilitiesAllocMachines(s390_machines,
|
|
|
|
ARRAY_CARDINALITY(s390_machines));
|
|
|
|
if (!machines)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:09:16 +00:00
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_S390X,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_S390X],
|
2016-12-20 09:10:05 +00:00
|
|
|
NULL,
|
2012-06-29 15:02:07 +00:00
|
|
|
ARRAY_CARDINALITY(s390_machines),
|
|
|
|
machines);
|
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:38:10 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
2012-06-29 15:02:07 +00:00
|
|
|
goto error;
|
2017-06-29 12:49:33 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
|
|
|
|
NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
2012-06-29 15:02:07 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
error:
|
2012-06-29 15:02:07 +00:00
|
|
|
virCapabilitiesFreeMachines(machines, ARRAY_CARDINALITY(s390_machines));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-30 19:41:14 +00:00
|
|
|
static int testQemuAddArmGuest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
static const char *machines[] = { "vexpress-a9",
|
|
|
|
"vexpress-a15",
|
|
|
|
"versatilepb" };
|
|
|
|
virCapsGuestMachinePtr *capsmachines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
capsmachines = virCapabilitiesAllocMachines(machines,
|
|
|
|
ARRAY_CARDINALITY(machines));
|
|
|
|
if (!capsmachines)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:09:16 +00:00
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_ARMV7L,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_ARM],
|
2016-12-20 09:10:05 +00:00
|
|
|
NULL,
|
2013-07-30 19:41:14 +00:00
|
|
|
ARRAY_CARDINALITY(machines),
|
|
|
|
capsmachines);
|
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:38:10 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
2013-07-30 19:41:14 +00:00
|
|
|
goto error;
|
2017-06-29 12:49:33 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
|
|
|
|
NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
2013-07-30 19:41:14 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
error:
|
2013-07-30 19:41:14 +00:00
|
|
|
virCapabilitiesFreeMachines(capsmachines, ARRAY_CARDINALITY(machines));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-01-02 10:42:56 +00:00
|
|
|
static int testQemuAddAARCH64Guest(virCapsPtr caps)
|
|
|
|
{
|
|
|
|
static const char *machines[] = { "virt"};
|
|
|
|
virCapsGuestMachinePtr *capsmachines = NULL;
|
|
|
|
virCapsGuestPtr guest;
|
|
|
|
|
|
|
|
capsmachines = virCapabilitiesAllocMachines(machines,
|
|
|
|
ARRAY_CARDINALITY(machines));
|
|
|
|
if (!capsmachines)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:09:16 +00:00
|
|
|
guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM, VIR_ARCH_AARCH64,
|
2017-04-06 16:33:52 +00:00
|
|
|
QEMUBinList[TEST_UTILS_QEMU_BIN_AARCH64],
|
2016-12-20 09:10:05 +00:00
|
|
|
NULL,
|
2014-01-02 10:42:56 +00:00
|
|
|
ARRAY_CARDINALITY(machines),
|
|
|
|
capsmachines);
|
|
|
|
if (!guest)
|
|
|
|
goto error;
|
|
|
|
|
2015-04-17 22:38:10 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU, NULL, NULL, 0, NULL))
|
2014-01-02 10:42:56 +00:00
|
|
|
goto error;
|
2017-06-29 12:49:33 +00:00
|
|
|
if (!virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
|
|
|
|
NULL, NULL, 0, NULL))
|
|
|
|
goto error;
|
2014-01-02 10:42:56 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
error:
|
2014-01-02 10:42:56 +00:00
|
|
|
virCapabilitiesFreeMachines(capsmachines, ARRAY_CARDINALITY(machines));
|
|
|
|
return -1;
|
|
|
|
}
|
2013-03-05 15:17:24 +00:00
|
|
|
|
2014-03-18 08:13:43 +00:00
|
|
|
virCapsPtr testQemuCapsInit(void)
|
|
|
|
{
|
2008-05-16 16:51:30 +00:00
|
|
|
virCapsPtr caps;
|
|
|
|
|
2015-03-23 16:19:28 +00:00
|
|
|
if (!(caps = virCapabilitiesNew(VIR_ARCH_X86_64, false, false)))
|
2008-05-16 16:51:30 +00:00
|
|
|
return NULL;
|
|
|
|
|
2014-09-03 17:06:55 +00:00
|
|
|
/* Add dummy 'none' security_driver. This is equal to setting
|
|
|
|
* security_driver = "none" in qemu.conf. */
|
|
|
|
if (VIR_ALLOC_N(caps->host.secModels, 1) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
caps->host.nsecModels = 1;
|
|
|
|
|
|
|
|
if (VIR_STRDUP(caps->host.secModels[0].model, "none") < 0 ||
|
|
|
|
VIR_STRDUP(caps->host.secModels[0].doi, "0") < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-03-23 16:19:28 +00:00
|
|
|
if (!(cpuDefault = virCPUDefCopy(&cpuDefaultData)) ||
|
2016-09-13 20:27:09 +00:00
|
|
|
!(cpuHaswell = virCPUDefCopy(&cpuHaswellData)) ||
|
2017-05-17 14:39:16 +00:00
|
|
|
!(cpuPower8 = virCPUDefCopy(&cpuPower8Data)) ||
|
|
|
|
!(cpuPower9 = virCPUDefCopy(&cpuPower9Data)))
|
2015-03-23 16:19:28 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2016-08-04 11:16:55 +00:00
|
|
|
qemuTestSetHostCPU(caps, NULL);
|
2015-03-23 16:19:28 +00:00
|
|
|
|
tests: Create full host NUMA topology in more cases
vircapstest has code to add a full host NUMA topology, that
is, one that includes all information about nodes and CPUs
including IDs; testQemuCapsInit(), which is used to create a
mock virCapsPtr for QEMU tests, however, just fakes it by
setting nnumaCell_max to some number.
While the latter approach has served us well so far, we're
going to need all the information to be filled in soon. In
order to do that, we can just move the existing code from
vircapstest to testutils and, with some renaming and
trivial tweaking, use it as-is.
Interestingly, the NUMA topology generated by the function
is rigged up so that the NUMA nodes aren't (necessarily)
numbered starting from 0, which is a nice way to spot
mistaken assumptions in our codebase.
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
2018-04-10 15:42:14 +00:00
|
|
|
/*
|
|
|
|
* Build a NUMA topology with cell_id (NUMA node id
|
|
|
|
* being 3(0 + 3),4(1 + 3), 5 and 6
|
|
|
|
*/
|
|
|
|
if (virTestCapsBuildNUMATopology(caps, 3) < 0)
|
|
|
|
goto cleanup;
|
2015-07-24 14:06:33 +00:00
|
|
|
|
2016-12-19 22:52:33 +00:00
|
|
|
if (testQemuAddI686Guest(caps) < 0)
|
2008-05-16 16:51:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2016-12-19 22:52:33 +00:00
|
|
|
if (testQemuAddX86_64Guest(caps) < 0)
|
2008-05-16 16:51:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2011-12-12 23:39:33 +00:00
|
|
|
if (testQemuAddPPC64Guest(caps))
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-02-26 17:15:54 +00:00
|
|
|
if (testQemuAddPPC64LEGuest(caps))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-03-14 04:49:43 +00:00
|
|
|
if (testQemuAddPPCGuest(caps))
|
|
|
|
goto cleanup;
|
|
|
|
|
2018-08-22 09:15:27 +00:00
|
|
|
if (testQemuAddRISCV32Guest(caps) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (testQemuAddRISCV64Guest(caps) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-06-29 15:02:07 +00:00
|
|
|
if (testQemuAddS390Guest(caps))
|
|
|
|
goto cleanup;
|
|
|
|
|
2013-07-30 19:41:14 +00:00
|
|
|
if (testQemuAddArmGuest(caps))
|
|
|
|
goto cleanup;
|
|
|
|
|
2014-01-02 10:42:56 +00:00
|
|
|
if (testQemuAddAARCH64Guest(caps))
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-11-30 19:01:31 +00:00
|
|
|
if (virTestGetDebug()) {
|
2009-09-10 10:07:20 +00:00
|
|
|
char *caps_str;
|
|
|
|
|
|
|
|
caps_str = virCapabilitiesFormatXML(caps);
|
|
|
|
if (!caps_str)
|
|
|
|
goto cleanup;
|
|
|
|
|
2015-04-23 17:38:00 +00:00
|
|
|
VIR_TEST_DEBUG("QEMU driver capabilities:\n%s", caps_str);
|
2009-09-10 10:07:20 +00:00
|
|
|
|
|
|
|
VIR_FREE(caps_str);
|
|
|
|
}
|
|
|
|
|
2008-05-16 16:51:30 +00:00
|
|
|
return caps;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2016-08-04 11:16:55 +00:00
|
|
|
caps->host.cpu = NULL;
|
|
|
|
virCPUDefFree(cpuDefault);
|
|
|
|
virCPUDefFree(cpuHaswell);
|
2016-09-13 20:27:09 +00:00
|
|
|
virCPUDefFree(cpuPower8);
|
2013-02-01 12:26:18 +00:00
|
|
|
virObjectUnref(caps);
|
2008-05-16 16:51:30 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-05-17 10:34:24 +00:00
|
|
|
|
|
|
|
|
2016-08-04 11:16:55 +00:00
|
|
|
void
|
|
|
|
qemuTestSetHostArch(virCapsPtr caps,
|
|
|
|
virArch arch)
|
|
|
|
{
|
|
|
|
if (arch == VIR_ARCH_NONE)
|
|
|
|
arch = VIR_ARCH_X86_64;
|
|
|
|
caps->host.arch = arch;
|
|
|
|
qemuTestSetHostCPU(caps, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
qemuTestSetHostCPU(virCapsPtr caps,
|
|
|
|
virCPUDefPtr cpu)
|
|
|
|
{
|
|
|
|
virArch arch = caps->host.arch;
|
|
|
|
|
|
|
|
if (!cpu) {
|
|
|
|
if (ARCH_IS_X86(arch))
|
|
|
|
cpu = cpuDefault;
|
2016-09-13 20:27:09 +00:00
|
|
|
else if (ARCH_IS_PPC64(arch))
|
|
|
|
cpu = cpuPower8;
|
2016-08-04 11:16:55 +00:00
|
|
|
}
|
|
|
|
|
2018-08-28 14:04:13 +00:00
|
|
|
unsetenv("VIR_TEST_MOCK_FAKE_HOST_CPU");
|
2017-07-21 12:24:51 +00:00
|
|
|
if (cpu) {
|
2016-08-04 11:16:55 +00:00
|
|
|
caps->host.arch = cpu->arch;
|
2017-07-21 12:24:51 +00:00
|
|
|
if (cpu->model)
|
|
|
|
setenv("VIR_TEST_MOCK_FAKE_HOST_CPU", cpu->model, 1);
|
|
|
|
}
|
2016-08-04 11:16:55 +00:00
|
|
|
caps->host.cpu = cpu;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-06-27 14:39:27 +00:00
|
|
|
virQEMUCapsPtr
|
2018-04-04 07:17:52 +00:00
|
|
|
qemuTestParseCapabilitiesArch(virArch arch,
|
|
|
|
const char *capsFile)
|
2014-06-27 14:39:27 +00:00
|
|
|
{
|
|
|
|
virQEMUCapsPtr qemuCaps = NULL;
|
|
|
|
|
2016-04-28 15:02:38 +00:00
|
|
|
if (!(qemuCaps = virQEMUCapsNew()) ||
|
2018-04-04 07:17:52 +00:00
|
|
|
virQEMUCapsLoadCache(arch, qemuCaps, capsFile) < 0)
|
2014-06-27 14:39:27 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
return qemuCaps;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virObjectUnref(qemuCaps);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-09-15 06:16:02 +00:00
|
|
|
|
2018-04-04 07:17:52 +00:00
|
|
|
|
|
|
|
virQEMUCapsPtr
|
|
|
|
qemuTestParseCapabilities(virCapsPtr caps,
|
|
|
|
const char *capsFile)
|
|
|
|
{
|
|
|
|
if (!caps)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return qemuTestParseCapabilitiesArch(caps->host.arch, capsFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
void qemuTestDriverFree(virQEMUDriver *driver)
|
|
|
|
{
|
2015-09-22 14:12:39 +00:00
|
|
|
virMutexDestroy(&driver->lock);
|
2017-03-06 07:27:23 +00:00
|
|
|
if (driver->config) {
|
|
|
|
virFileDeleteTree(driver->config->stateDir);
|
|
|
|
virFileDeleteTree(driver->config->configDir);
|
|
|
|
}
|
2017-07-19 15:01:56 +00:00
|
|
|
virObjectUnref(driver->qemuCapsCache);
|
2015-09-15 06:16:02 +00:00
|
|
|
virObjectUnref(driver->xmlopt);
|
|
|
|
virObjectUnref(driver->caps);
|
|
|
|
virObjectUnref(driver->config);
|
2016-07-29 16:06:51 +00:00
|
|
|
virObjectUnref(driver->securityManager);
|
2015-09-15 06:16:02 +00:00
|
|
|
}
|
|
|
|
|
2017-07-19 15:01:56 +00:00
|
|
|
int qemuTestCapsCacheInsert(virFileCachePtr cache,
|
2015-09-09 14:03:14 +00:00
|
|
|
virQEMUCapsPtr caps)
|
|
|
|
{
|
2017-04-11 12:02:06 +00:00
|
|
|
size_t i;
|
|
|
|
virQEMUCapsPtr tmpCaps;
|
2015-09-09 14:03:14 +00:00
|
|
|
|
|
|
|
if (caps) {
|
2017-04-11 12:02:06 +00:00
|
|
|
tmpCaps = caps;
|
2015-09-09 14:03:14 +00:00
|
|
|
} else {
|
2017-04-11 12:02:06 +00:00
|
|
|
if (!(tmpCaps = virQEMUCapsNew()))
|
2015-09-09 14:03:14 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
for (i = 0; i < ARRAY_CARDINALITY(QEMUBinList); i++) {
|
|
|
|
virObjectRef(tmpCaps);
|
2017-07-19 15:01:56 +00:00
|
|
|
if (virFileCacheInsertData(cache, QEMUBinList[i], tmpCaps) < 0) {
|
2017-04-11 12:02:06 +00:00
|
|
|
virObjectUnref(tmpCaps);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2015-09-09 14:03:14 +00:00
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
if (!caps)
|
|
|
|
virObjectUnref(tmpCaps);
|
2015-09-09 14:03:14 +00:00
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
return 0;
|
2015-09-09 14:03:14 +00:00
|
|
|
}
|
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
|
2017-03-06 07:27:23 +00:00
|
|
|
# define STATEDIRTEMPLATE abs_builddir "/qemustatedir-XXXXXX"
|
|
|
|
# define CONFIGDIRTEMPLATE abs_builddir "/qemuconfigdir-XXXXXX"
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
int qemuTestDriverInit(virQEMUDriver *driver)
|
|
|
|
{
|
2016-03-23 15:19:26 +00:00
|
|
|
virSecurityManagerPtr mgr = NULL;
|
2017-03-06 07:27:23 +00:00
|
|
|
char statedir[] = STATEDIRTEMPLATE;
|
|
|
|
char configdir[] = CONFIGDIRTEMPLATE;
|
2016-03-23 15:19:26 +00:00
|
|
|
|
2016-01-18 08:11:19 +00:00
|
|
|
memset(driver, 0, sizeof(*driver));
|
|
|
|
|
2015-09-22 14:12:39 +00:00
|
|
|
if (virMutexInit(&driver->lock) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
driver->config = virQEMUDriverConfigNew(false);
|
|
|
|
if (!driver->config)
|
2015-09-22 14:12:39 +00:00
|
|
|
goto error;
|
2015-09-15 06:16:02 +00:00
|
|
|
|
2017-03-06 07:27:23 +00:00
|
|
|
/* Do this early so that qemuTestDriverFree() doesn't see (unlink) the real
|
|
|
|
* dirs. */
|
|
|
|
VIR_FREE(driver->config->stateDir);
|
|
|
|
VIR_FREE(driver->config->configDir);
|
|
|
|
|
2016-03-15 12:54:24 +00:00
|
|
|
/* Overwrite some default paths so it's consistent for tests. */
|
|
|
|
VIR_FREE(driver->config->libDir);
|
|
|
|
VIR_FREE(driver->config->channelTargetDir);
|
|
|
|
if (VIR_STRDUP(driver->config->libDir, "/tmp/lib") < 0 ||
|
|
|
|
VIR_STRDUP(driver->config->channelTargetDir, "/tmp/channel") < 0)
|
|
|
|
goto error;
|
|
|
|
|
2017-03-06 07:27:23 +00:00
|
|
|
if (!mkdtemp(statedir)) {
|
|
|
|
virFilePrintf(stderr, "Cannot create fake stateDir");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_STRDUP(driver->config->stateDir, statedir) < 0) {
|
|
|
|
rmdir(statedir);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mkdtemp(configdir)) {
|
|
|
|
virFilePrintf(stderr, "Cannot create fake configDir");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_STRDUP(driver->config->configDir, configdir) < 0) {
|
|
|
|
rmdir(configdir);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
driver->caps = testQemuCapsInit();
|
|
|
|
if (!driver->caps)
|
|
|
|
goto error;
|
|
|
|
|
2015-09-09 14:03:15 +00:00
|
|
|
/* Using /dev/null for libDir and cacheDir automatically produces errors
|
|
|
|
* upon attempt to use any of them */
|
2017-12-12 15:23:41 +00:00
|
|
|
driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null", 0, 0, 0);
|
2015-09-09 14:03:15 +00:00
|
|
|
if (!driver->qemuCapsCache)
|
|
|
|
goto error;
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
driver->xmlopt = virQEMUDriverCreateXMLConf(driver);
|
|
|
|
if (!driver->xmlopt)
|
|
|
|
goto error;
|
|
|
|
|
2017-04-11 12:02:06 +00:00
|
|
|
if (qemuTestCapsCacheInsert(driver->qemuCapsCache, NULL) < 0)
|
2015-09-09 14:03:15 +00:00
|
|
|
goto error;
|
|
|
|
|
2018-09-05 14:30:15 +00:00
|
|
|
if (!(mgr = virSecurityManagerNew("none", "qemu", NULL,
|
2016-03-23 15:19:26 +00:00
|
|
|
VIR_SECURITY_MANAGER_PRIVILEGED)))
|
|
|
|
goto error;
|
|
|
|
if (!(driver->securityManager = virSecurityManagerNewStack(mgr)))
|
|
|
|
goto error;
|
|
|
|
|
2015-09-15 06:16:02 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
2016-03-23 15:19:26 +00:00
|
|
|
virObjectUnref(mgr);
|
2015-09-15 06:16:02 +00:00
|
|
|
qemuTestDriverFree(driver);
|
|
|
|
return -1;
|
|
|
|
}
|
2015-09-09 14:03:14 +00:00
|
|
|
|
2016-05-10 09:35:43 +00:00
|
|
|
int
|
|
|
|
testQemuCapsSetGIC(virQEMUCapsPtr qemuCaps,
|
|
|
|
int gic)
|
|
|
|
{
|
|
|
|
virGICCapability *gicCapabilities = NULL;
|
|
|
|
size_t ngicCapabilities = 0;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(gicCapabilities, 2) < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
# define IMPL_BOTH \
|
|
|
|
VIR_GIC_IMPLEMENTATION_KERNEL|VIR_GIC_IMPLEMENTATION_EMULATED
|
|
|
|
|
|
|
|
if (gic & GIC_V2) {
|
|
|
|
gicCapabilities[ngicCapabilities].version = VIR_GIC_VERSION_2;
|
|
|
|
gicCapabilities[ngicCapabilities].implementation = IMPL_BOTH;
|
|
|
|
ngicCapabilities++;
|
|
|
|
}
|
|
|
|
if (gic & GIC_V3) {
|
|
|
|
gicCapabilities[ngicCapabilities].version = VIR_GIC_VERSION_3;
|
|
|
|
gicCapabilities[ngicCapabilities].implementation = IMPL_BOTH;
|
|
|
|
ngicCapabilities++;
|
|
|
|
}
|
|
|
|
|
|
|
|
# undef IMPL_BOTH
|
|
|
|
|
|
|
|
virQEMUCapsSetGICCapabilities(qemuCaps,
|
|
|
|
gicCapabilities, ngicCapabilities);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-06-26 09:37:51 +00:00
|
|
|
#endif
|
2018-04-18 08:47:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
testQemuGetLatestCapsForArch(const char *dirname,
|
|
|
|
const char *arch,
|
|
|
|
const char *suffix)
|
|
|
|
{
|
|
|
|
struct dirent *ent;
|
|
|
|
DIR *dir = NULL;
|
|
|
|
int rc;
|
|
|
|
char *fullsuffix = NULL;
|
|
|
|
char *tmp = NULL;
|
|
|
|
unsigned long maxver = 0;
|
|
|
|
unsigned long ver;
|
|
|
|
const char *maxname = NULL;
|
|
|
|
char *ret = NULL;
|
|
|
|
|
|
|
|
if (virAsprintf(&fullsuffix, "%s.%s", arch, suffix) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virDirOpen(&dir, dirname) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
while ((rc = virDirRead(dir, &ent, dirname)) > 0) {
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
|
|
|
|
if ((rc = VIR_STRDUP(tmp, STRSKIP(ent->d_name, "caps_"))) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (rc == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (virFileStripSuffix(tmp, fullsuffix) != 1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (virParseVersionString(tmp, &ver, false) < 0) {
|
|
|
|
VIR_TEST_DEBUG("skipping caps file '%s'\n", ent->d_name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ver > maxver) {
|
|
|
|
maxname = ent->d_name;
|
|
|
|
maxver = ver;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!maxname) {
|
|
|
|
VIR_TEST_VERBOSE("failed to find capabilities for '%s' in '%s'\n",
|
|
|
|
arch, dirname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ignore_value(virAsprintf(&ret, "%s/%s", dirname, maxname));
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(tmp);
|
|
|
|
VIR_FREE(fullsuffix);
|
|
|
|
virDirClose(&dir);
|
|
|
|
return ret;
|
|
|
|
}
|