1 #include <config.h>
2 #ifdef WITH_QEMU
3
4 # include "testutilsqemu.h"
5 # include "testutilshostcpus.h"
6 # include "testutils.h"
7 # include "viralloc.h"
8 # include "cpu_conf.h"
9 # include "qemu/qemu_driver.h"
10 # include "qemu/qemu_domain.h"
11 # define LIBVIRT_QEMU_CAPSPRIV_H_ALLOW
12 # include "qemu/qemu_capspriv.h"
13 # include "virstring.h"
14 # include "virfilecache.h"
15 # include "virutil.h"
16
17 # define VIR_FROM_THIS VIR_FROM_QEMU
18
19 virCPUDef *cpuDefault;
20 virCPUDef *cpuHaswell;
21 virCPUDef *cpuPower8;
22 virCPUDef *cpuPower9;
23
24
25 static const char *qemu_emulators[VIR_ARCH_LAST] = {
26 [VIR_ARCH_I686] = "/usr/bin/qemu-system-i386",
27 [VIR_ARCH_X86_64] = "/usr/bin/qemu-system-x86_64",
28 [VIR_ARCH_AARCH64] = "/usr/bin/qemu-system-aarch64",
29 [VIR_ARCH_ARMV7L] = "/usr/bin/qemu-system-arm",
30 [VIR_ARCH_PPC64] = "/usr/bin/qemu-system-ppc64",
31 [VIR_ARCH_PPC] = "/usr/bin/qemu-system-ppc",
32 [VIR_ARCH_RISCV32] = "/usr/bin/qemu-system-riscv32",
33 [VIR_ARCH_RISCV64] = "/usr/bin/qemu-system-riscv64",
34 [VIR_ARCH_S390X] = "/usr/bin/qemu-system-s390x",
35 [VIR_ARCH_SPARC] = "/usr/bin/qemu-system-sparc",
36 };
37
38 static const virArch arch_alias[VIR_ARCH_LAST] = {
39 [VIR_ARCH_PPC64LE] = VIR_ARCH_PPC64,
40 [VIR_ARCH_ARMV6L] = VIR_ARCH_ARMV7L,
41 };
42
43 static const char *const i386_machines[] = {
44 "pc", "isapc", NULL
45 };
46 /**
47 * Oldest supported qemu-2.11 supports machine types back to pc-0.10.
48 */
49 static const char *const x86_64_machines[] = {
50 "pc", "isapc", "q35",
51 "pc-1.0", "pc-1.2",
52 "pc-i440fx-1.4", "pc-i440fx-2.1", "pc-i440fx-2.3", "pc-i440fx-2.5",
53 "pc-i440fx-2.6", "pc-i440fx-2.9", "pc-i440fx-2.12",
54 "pc-q35-2.3", "pc-q35-2.4", "pc-q35-2.5", "pc-q35-2.7", "pc-q35-2.10",
55 NULL
56 };
57 static const char *const aarch64_machines[] = {
58 "virt", "virt-2.6", "versatilepb", NULL
59 };
60 static const char *const arm_machines[] = {
61 "vexpress-a9", "vexpress-a15", "versatilepb", "virt", NULL
62 };
63 static const char *const ppc64_machines[] = {
64 "pseries", NULL
65 };
66 static const char *const ppc_machines[] = {
67 "g3beige", "mac99", "prep", "ppce500", NULL
68 };
69 static const char *const riscv32_machines[] = {
70 "spike_v1.10", "spike_v1.9.1", "sifive_e", "virt", "sifive_u", NULL
71 };
72 static const char *const riscv64_machines[] = {
73 "spike_v1.10", "spike_v1.9.1", "sifive_e", "virt", "sifive_u", NULL
74 };
75 static const char *const s390x_machines[] = {
76 "s390-ccw-virtio", NULL
77 };
78 static const char *const sparc_machines[] = {
79 "SS-5", "LX", "SPARCClassic", "SPARCbook",
80 "SS-10", "SS-20", "SS-4", "SS-600MP",
81 "Voyager", "leon3_generic", NULL
82 };
83
84 static const char *const *qemu_machines[VIR_ARCH_LAST] = {
85 [VIR_ARCH_I686] = i386_machines,
86 [VIR_ARCH_X86_64] = x86_64_machines,
87 [VIR_ARCH_AARCH64] = aarch64_machines,
88 [VIR_ARCH_ARMV7L] = arm_machines,
89 [VIR_ARCH_PPC64] = ppc64_machines,
90 [VIR_ARCH_PPC] = ppc_machines,
91 [VIR_ARCH_RISCV32] = riscv32_machines,
92 [VIR_ARCH_RISCV64] = riscv64_machines,
93 [VIR_ARCH_S390X] = s390x_machines,
94 [VIR_ARCH_SPARC] = sparc_machines,
95 };
96
97 static const char *const *kvm_machines[VIR_ARCH_LAST] = {
98 [VIR_ARCH_I686] = i386_machines,
99 [VIR_ARCH_X86_64] = x86_64_machines,
100 [VIR_ARCH_AARCH64] = aarch64_machines,
101 [VIR_ARCH_ARMV7L] = arm_machines,
102 [VIR_ARCH_PPC64] = ppc64_machines,
103 [VIR_ARCH_PPC] = ppc_machines,
104 [VIR_ARCH_RISCV32] = riscv32_machines,
105 [VIR_ARCH_RISCV64] = riscv64_machines,
106 [VIR_ARCH_S390X] = s390x_machines,
107 };
108
109 static const char *qemu_default_ram_id[VIR_ARCH_LAST] = {
110 [VIR_ARCH_I686] = "pc.ram",
111 [VIR_ARCH_X86_64] = "pc.ram",
112 [VIR_ARCH_AARCH64] = "mach-virt.ram",
113 [VIR_ARCH_ARMV7L] = "vexpress.highmem",
114 [VIR_ARCH_PPC64] = "ppc_spapr.ram",
115 [VIR_ARCH_PPC] = "ppc_spapr.ram",
116 [VIR_ARCH_S390X] = "s390.ram",
117 [VIR_ARCH_SPARC] = "sun4m.ram",
118 };
119
120 char *
virFindFileInPath(const char * file)121 virFindFileInPath(const char *file)
122 {
123 if (g_str_has_prefix(file, "qemu-system") ||
124 g_str_equal(file, "qemu-kvm")) {
125 return g_strdup_printf("/usr/bin/%s", file);
126 }
127
128 /* Nothing in tests should be relying on real files
129 * in host OS, so we return NULL to try to force
130 * an error in such a case
131 */
132 return NULL;
133 }
134
135
136 virCapsHostNUMA *
virCapabilitiesHostNUMANewHost(void)137 virCapabilitiesHostNUMANewHost(void)
138 {
139 /*
140 * Build a NUMA topology with cell_id (NUMA node id
141 * being 3(0 + 3),4(1 + 3), 5 and 6
142 */
143 return virTestCapsBuildNUMATopology(3);
144 }
145
146
147 static int
testQemuAddGuest(virCaps * caps,virArch arch)148 testQemuAddGuest(virCaps *caps,
149 virArch arch)
150 {
151 size_t nmachines;
152 virCapsGuestMachine **machines = NULL;
153 virCapsGuest *guest;
154 virArch emu_arch = arch;
155
156 if (arch_alias[arch] != VIR_ARCH_NONE)
157 emu_arch = arch_alias[arch];
158
159 if (qemu_emulators[emu_arch] == NULL)
160 return 0;
161
162 nmachines = g_strv_length((gchar **)qemu_machines[emu_arch]);
163 machines = virCapabilitiesAllocMachines(qemu_machines[emu_arch],
164 nmachines);
165 if (machines == NULL)
166 goto error;
167
168 guest = virCapabilitiesAddGuest(caps, VIR_DOMAIN_OSTYPE_HVM,
169 arch, qemu_emulators[emu_arch],
170 NULL, nmachines, machines);
171
172 machines = NULL;
173 nmachines = 0;
174
175 if (arch == VIR_ARCH_I686 ||
176 arch == VIR_ARCH_X86_64)
177 virCapabilitiesAddGuestFeature(guest, VIR_CAPS_GUEST_FEATURE_TYPE_CPUSELECTION);
178
179 virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_QEMU,
180 NULL, NULL, 0, NULL);
181
182 if (kvm_machines[emu_arch] != NULL) {
183 nmachines = g_strv_length((char **)kvm_machines[emu_arch]);
184 machines = virCapabilitiesAllocMachines(kvm_machines[emu_arch],
185 nmachines);
186 if (machines == NULL)
187 goto error;
188
189 virCapabilitiesAddGuestDomain(guest, VIR_DOMAIN_VIRT_KVM,
190 qemu_emulators[emu_arch],
191 NULL, nmachines, machines);
192 }
193
194 return 0;
195
196 error:
197 virCapabilitiesFreeMachines(machines, nmachines);
198 return -1;
199 }
200
201
testQemuCapsInit(void)202 virCaps *testQemuCapsInit(void)
203 {
204 virCaps *caps;
205 size_t i;
206
207 if (!(caps = virCapabilitiesNew(VIR_ARCH_X86_64, false, false)))
208 return NULL;
209
210 /* Add dummy 'none' security_driver. This is equal to setting
211 * security_driver = "none" in qemu.conf. */
212 caps->host.secModels = g_new0(virCapsHostSecModel, 1);
213 caps->host.nsecModels = 1;
214
215 caps->host.secModels[0].model = g_strdup("none");
216 caps->host.secModels[0].doi = g_strdup("0");
217
218 if (!(caps->host.numa = virCapabilitiesHostNUMANewHost()))
219 goto cleanup;
220
221 for (i = 0; i < VIR_ARCH_LAST; i++) {
222 if (testQemuAddGuest(caps, i) < 0)
223 goto cleanup;
224 }
225
226 if (virTestGetDebug()) {
227 g_autofree char *caps_str = NULL;
228
229 caps_str = virCapabilitiesFormatXML(caps);
230 if (!caps_str)
231 goto cleanup;
232
233 VIR_TEST_DEBUG("QEMU driver capabilities:\n%s", caps_str);
234 }
235
236 return caps;
237
238 cleanup:
239 caps->host.cpu = NULL;
240 virObjectUnref(caps);
241 return NULL;
242 }
243
244
245 void
qemuTestSetHostArch(virQEMUDriver * driver,virArch arch)246 qemuTestSetHostArch(virQEMUDriver *driver,
247 virArch arch)
248 {
249 if (arch == VIR_ARCH_NONE)
250 arch = VIR_ARCH_X86_64;
251
252 virTestHostArch = arch;
253 driver->hostarch = virArchFromHost();
254 driver->caps->host.arch = virArchFromHost();
255 qemuTestSetHostCPU(driver, arch, NULL);
256 }
257
258
259 void
qemuTestSetHostCPU(virQEMUDriver * driver,virArch arch,virCPUDef * cpu)260 qemuTestSetHostCPU(virQEMUDriver *driver,
261 virArch arch,
262 virCPUDef *cpu)
263 {
264 if (!cpu) {
265 if (ARCH_IS_X86(arch))
266 cpu = cpuDefault;
267 else if (ARCH_IS_PPC64(arch))
268 cpu = cpuPower8;
269 }
270
271 g_unsetenv("VIR_TEST_MOCK_FAKE_HOST_CPU");
272 if (cpu) {
273 if (cpu->model)
274 g_setenv("VIR_TEST_MOCK_FAKE_HOST_CPU", cpu->model, TRUE);
275 }
276 if (driver) {
277 if (cpu)
278 driver->caps->host.arch = cpu->arch;
279 driver->caps->host.cpu = cpu;
280
281 virCPUDefFree(driver->hostcpu);
282 if (cpu)
283 virCPUDefRef(cpu);
284 driver->hostcpu = cpu;
285 }
286 }
287
288
289 virQEMUCaps *
qemuTestParseCapabilitiesArch(virArch arch,const char * capsFile)290 qemuTestParseCapabilitiesArch(virArch arch,
291 const char *capsFile)
292 {
293 g_autoptr(virQEMUCaps) qemuCaps = NULL;
294 g_autofree char *binary = g_strdup_printf("/usr/bin/qemu-system-%s",
295 virArchToString(arch));
296
297 if (!(qemuCaps = virQEMUCapsNewBinary(binary)) ||
298 virQEMUCapsLoadCache(arch, qemuCaps, capsFile, true) < 0)
299 return NULL;
300
301 return g_steal_pointer(&qemuCaps);
302 }
303
304
qemuTestDriverFree(virQEMUDriver * driver)305 void qemuTestDriverFree(virQEMUDriver *driver)
306 {
307 virMutexDestroy(&driver->lock);
308 if (driver->config) {
309 virFileDeleteTree(driver->config->stateDir);
310 virFileDeleteTree(driver->config->configDir);
311 }
312 virObjectUnref(driver->qemuCapsCache);
313 virObjectUnref(driver->xmlopt);
314 virObjectUnref(driver->caps);
315 virObjectUnref(driver->config);
316 virObjectUnref(driver->securityManager);
317
318 virCPUDefFree(cpuDefault);
319 virCPUDefFree(cpuHaswell);
320 virCPUDefFree(cpuPower8);
321 virCPUDefFree(cpuPower9);
322 }
323
qemuTestCapsCacheInsert(virFileCache * cache,virQEMUCaps * caps)324 int qemuTestCapsCacheInsert(virFileCache *cache,
325 virQEMUCaps *caps)
326 {
327 size_t i, j;
328
329 for (i = 0; i < G_N_ELEMENTS(qemu_emulators); i++) {
330 virQEMUCaps *tmpCaps;
331 if (qemu_emulators[i] == NULL)
332 continue;
333 if (caps) {
334 tmpCaps = virQEMUCapsNewCopy(caps);
335 } else {
336 tmpCaps = virQEMUCapsNew();
337 }
338
339 if (!tmpCaps)
340 return -1;
341
342 if (!virQEMUCapsHasMachines(tmpCaps)) {
343 const char *defaultRAMid = NULL;
344
345 /* default-ram-id appeared in QEMU 5.2.0. Reflect
346 * this in our capabilities, i.e. set it for new
347 * enough versions only. */
348 if (virQEMUCapsGetVersion(tmpCaps) >= 5002000)
349 defaultRAMid = qemu_default_ram_id[i];
350
351 virQEMUCapsSetArch(tmpCaps, i);
352
353 for (j = 0; qemu_machines[i][j] != NULL; j++) {
354 virQEMUCapsAddMachine(tmpCaps,
355 VIR_DOMAIN_VIRT_QEMU,
356 qemu_machines[i][j],
357 NULL,
358 NULL,
359 0,
360 false,
361 false,
362 true,
363 defaultRAMid,
364 false);
365 virQEMUCapsSet(tmpCaps, QEMU_CAPS_TCG);
366 }
367 if (kvm_machines[i] != NULL) {
368 for (j = 0; kvm_machines[i][j] != NULL; j++) {
369 virQEMUCapsAddMachine(tmpCaps,
370 VIR_DOMAIN_VIRT_KVM,
371 kvm_machines[i][j],
372 NULL,
373 NULL,
374 0,
375 false,
376 false,
377 true,
378 defaultRAMid,
379 false);
380 virQEMUCapsSet(tmpCaps, QEMU_CAPS_KVM);
381 }
382 }
383 }
384
385 if (virFileCacheInsertData(cache, qemu_emulators[i], tmpCaps) < 0) {
386 virObjectUnref(tmpCaps);
387 return -1;
388 }
389 }
390
391 return 0;
392 }
393
394
395 # define STATEDIRTEMPLATE abs_builddir "/qemustatedir-XXXXXX"
396 # define CONFIGDIRTEMPLATE abs_builddir "/qemuconfigdir-XXXXXX"
397
qemuTestDriverInit(virQEMUDriver * driver)398 int qemuTestDriverInit(virQEMUDriver *driver)
399 {
400 virSecurityManager *mgr = NULL;
401 char statedir[] = STATEDIRTEMPLATE;
402 char configdir[] = CONFIGDIRTEMPLATE;
403
404 memset(driver, 0, sizeof(*driver));
405
406 if (!(cpuDefault = virCPUDefCopy(&cpuDefaultData)) ||
407 !(cpuHaswell = virCPUDefCopy(&cpuHaswellData)) ||
408 !(cpuPower8 = virCPUDefCopy(&cpuPower8Data)) ||
409 !(cpuPower9 = virCPUDefCopy(&cpuPower9Data)))
410 return -1;
411
412 if (virMutexInit(&driver->lock) < 0)
413 return -1;
414
415 driver->hostarch = virArchFromHost();
416 driver->config = virQEMUDriverConfigNew(false, NULL);
417 if (!driver->config)
418 goto error;
419
420 /* Do this early so that qemuTestDriverFree() doesn't see (unlink) the real
421 * dirs. */
422 VIR_FREE(driver->config->stateDir);
423 VIR_FREE(driver->config->configDir);
424
425 /* Overwrite some default paths so it's consistent for tests. */
426 VIR_FREE(driver->config->libDir);
427 VIR_FREE(driver->config->channelTargetDir);
428 driver->config->libDir = g_strdup("/tmp/lib");
429 driver->config->channelTargetDir = g_strdup("/tmp/channel");
430
431 if (!g_mkdtemp(statedir)) {
432 fprintf(stderr, "Cannot create fake stateDir");
433 goto error;
434 }
435
436 driver->config->stateDir = g_strdup(statedir);
437
438 if (!g_mkdtemp(configdir)) {
439 fprintf(stderr, "Cannot create fake configDir");
440 goto error;
441 }
442
443 driver->config->configDir = g_strdup(configdir);
444
445 driver->caps = testQemuCapsInit();
446 if (!driver->caps)
447 goto error;
448
449 /* Using /dev/null for libDir and cacheDir automatically produces errors
450 * upon attempt to use any of them */
451 driver->qemuCapsCache = virQEMUCapsCacheNew("/dev/null", "/dev/null", 0, 0);
452 if (!driver->qemuCapsCache)
453 goto error;
454
455 driver->xmlopt = virQEMUDriverCreateXMLConf(driver, "none");
456 if (!driver->xmlopt)
457 goto error;
458
459 if (qemuTestCapsCacheInsert(driver->qemuCapsCache, NULL) < 0)
460 goto error;
461
462 if (!(mgr = virSecurityManagerNew("none", "qemu",
463 VIR_SECURITY_MANAGER_PRIVILEGED)))
464 goto error;
465 if (!(driver->securityManager = virSecurityManagerNewStack(mgr)))
466 goto error;
467
468 qemuTestSetHostCPU(driver, driver->hostarch, NULL);
469
470 return 0;
471
472 error:
473 virObjectUnref(mgr);
474 qemuTestDriverFree(driver);
475 return -1;
476 }
477
478 int
testQemuCapsSetGIC(virQEMUCaps * qemuCaps,int gic)479 testQemuCapsSetGIC(virQEMUCaps *qemuCaps,
480 int gic)
481 {
482 virGICCapability *gicCapabilities = NULL;
483 size_t ngicCapabilities = 0;
484
485 gicCapabilities = g_new0(virGICCapability, 2);
486
487 # define IMPL_BOTH \
488 VIR_GIC_IMPLEMENTATION_KERNEL|VIR_GIC_IMPLEMENTATION_EMULATED
489
490 if (gic & GIC_V2) {
491 gicCapabilities[ngicCapabilities].version = VIR_GIC_VERSION_2;
492 gicCapabilities[ngicCapabilities].implementation = IMPL_BOTH;
493 ngicCapabilities++;
494 }
495 if (gic & GIC_V3) {
496 gicCapabilities[ngicCapabilities].version = VIR_GIC_VERSION_3;
497 gicCapabilities[ngicCapabilities].implementation = IMPL_BOTH;
498 ngicCapabilities++;
499 }
500
501 # undef IMPL_BOTH
502
503 virQEMUCapsSetGICCapabilities(qemuCaps,
504 gicCapabilities, ngicCapabilities);
505
506 return 0;
507 }
508
509 #endif
510
511
512 char *
testQemuGetLatestCapsForArch(const char * arch,const char * suffix)513 testQemuGetLatestCapsForArch(const char *arch,
514 const char *suffix)
515 {
516 struct dirent *ent;
517 g_autoptr(DIR) dir = NULL;
518 int rc;
519 g_autofree char *fullsuffix = NULL;
520 unsigned long maxver = 0;
521 unsigned long ver;
522 g_autofree char *maxname = NULL;
523
524 fullsuffix = g_strdup_printf("%s.%s", arch, suffix);
525
526 if (virDirOpen(&dir, TEST_QEMU_CAPS_PATH) < 0)
527 return NULL;
528
529 while ((rc = virDirRead(dir, &ent, TEST_QEMU_CAPS_PATH)) > 0) {
530 g_autofree char *tmp = NULL;
531
532 tmp = g_strdup(STRSKIP(ent->d_name, "caps_"));
533
534 if (!tmp)
535 continue;
536
537 if (!virStringStripSuffix(tmp, fullsuffix))
538 continue;
539
540 if (virParseVersionString(tmp, &ver, false) < 0) {
541 VIR_TEST_DEBUG("skipping caps file '%s'", ent->d_name);
542 continue;
543 }
544
545 if (ver > maxver) {
546 g_free(maxname);
547 maxname = g_strdup(ent->d_name);
548 maxver = ver;
549 }
550 }
551
552 if (rc < 0)
553 return NULL;
554
555 if (!maxname) {
556 VIR_TEST_VERBOSE("failed to find capabilities for '%s' in '%s'",
557 arch, TEST_QEMU_CAPS_PATH);
558 return NULL;
559 }
560
561 return g_strdup_printf("%s/%s", TEST_QEMU_CAPS_PATH, maxname);
562 }
563
564
565 GHashTable *
testQemuGetLatestCaps(void)566 testQemuGetLatestCaps(void)
567 {
568 const char *archs[] = {
569 "aarch64",
570 "ppc64",
571 "riscv64",
572 "s390x",
573 "x86_64",
574 };
575 g_autoptr(GHashTable) capslatest = virHashNew(g_free);
576 size_t i;
577
578 VIR_TEST_VERBOSE("");
579
580 for (i = 0; i < G_N_ELEMENTS(archs); ++i) {
581 char *cap = testQemuGetLatestCapsForArch(archs[i], "xml");
582
583 if (!cap || virHashAddEntry(capslatest, archs[i], cap) < 0)
584 return NULL;
585
586 VIR_TEST_VERBOSE("latest caps for %s: %s", archs[i], cap);
587 }
588
589 VIR_TEST_VERBOSE("");
590
591 return g_steal_pointer(&capslatest);
592 }
593
594
595 int
testQemuCapsIterate(const char * suffix,testQemuCapsIterateCallback callback,void * opaque)596 testQemuCapsIterate(const char *suffix,
597 testQemuCapsIterateCallback callback,
598 void *opaque)
599 {
600 struct dirent *ent;
601 g_autoptr(DIR) dir = NULL;
602 int rc;
603 bool fail = false;
604
605 if (!callback)
606 return 0;
607
608 /* Validate suffix */
609 if (!STRPREFIX(suffix, ".")) {
610 VIR_TEST_VERBOSE("malformed suffix '%s'", suffix);
611 return -1;
612 }
613
614 if (virDirOpen(&dir, TEST_QEMU_CAPS_PATH) < 0)
615 return -1;
616
617 while ((rc = virDirRead(dir, &ent, TEST_QEMU_CAPS_PATH)) > 0) {
618 g_autofree char *tmp = g_strdup(ent->d_name);
619 char *version = NULL;
620 char *archName = NULL;
621
622 /* Strip the trailing suffix, moving on if it's not present */
623 if (!virStringStripSuffix(tmp, suffix))
624 continue;
625
626 /* Strip the leading prefix */
627 if (!(version = STRSKIP(tmp, "caps_"))) {
628 VIR_TEST_VERBOSE("malformed file name '%s'", ent->d_name);
629 return -1;
630 }
631
632 /* Find the last dot */
633 if (!(archName = strrchr(tmp, '.'))) {
634 VIR_TEST_VERBOSE("malformed file name '%s'", ent->d_name);
635 return -1;
636 }
637
638 /* The version number and the architecture name are separated by
639 * a dot: overwriting that dot with \0 results in both being usable
640 * as independent, null-terminated strings */
641 archName[0] = '\0';
642 archName++;
643
644 /* Run the user-provided callback.
645 *
646 * We skip the dot that, as verified earlier, starts the suffix
647 * to make it nicer to rebuild the original file name from inside
648 * the callback.
649 */
650 if (callback(TEST_QEMU_CAPS_PATH, "caps", version,
651 archName, suffix + 1, opaque) < 0)
652 fail = true;
653 }
654
655 if (rc < 0 || fail)
656 return -1;
657
658 return 0;
659 }
660
661
662 void
testQemuInfoSetArgs(struct testQemuInfo * info,struct testQemuConf * conf,...)663 testQemuInfoSetArgs(struct testQemuInfo *info,
664 struct testQemuConf *conf, ...)
665 {
666 va_list argptr;
667 testQemuInfoArgName argname;
668 int flag;
669
670 if (!(info->args.fakeCaps = virQEMUCapsNew()))
671 abort();
672
673 info->conf = conf;
674 info->args.newargs = true;
675
676 va_start(argptr, conf);
677 while ((argname = va_arg(argptr, testQemuInfoArgName)) != ARG_END) {
678 switch (argname) {
679 case ARG_QEMU_CAPS:
680 info->args.fakeCapsUsed = true;
681
682 while ((flag = va_arg(argptr, int)) < QEMU_CAPS_LAST)
683 virQEMUCapsSet(info->args.fakeCaps, flag);
684 break;
685
686 case ARG_GIC:
687 info->args.gic = va_arg(argptr, int);
688 break;
689
690 case ARG_MIGRATE_FROM:
691 info->migrateFrom = va_arg(argptr, char *);
692 break;
693
694 case ARG_MIGRATE_FD:
695 info->migrateFd = va_arg(argptr, int);
696 break;
697
698 case ARG_FLAGS:
699 info->flags = va_arg(argptr, int);
700 break;
701
702 case ARG_PARSEFLAGS:
703 info->parseFlags = va_arg(argptr, int);
704 break;
705
706 case ARG_CAPS_ARCH:
707 info->args.capsarch = va_arg(argptr, char *);
708 break;
709
710 case ARG_CAPS_VER:
711 info->args.capsver = va_arg(argptr, char *);
712 break;
713
714 case ARG_END:
715 default:
716 info->args.invalidarg = true;
717 break;
718 }
719
720 if (info->args.invalidarg)
721 break;
722 }
723
724 va_end(argptr);
725 }
726
727
728 int
testQemuInfoInitArgs(struct testQemuInfo * info)729 testQemuInfoInitArgs(struct testQemuInfo *info)
730 {
731 g_autofree char *capsfile = NULL;
732
733 if (!info->args.newargs)
734 return 0;
735
736 info->args.newargs = false;
737
738 if (info->args.invalidarg) {
739 fprintf(stderr, "Invalid argument encountered by 'testQemuInfoSetArgs'\n");
740 return -1;
741 }
742
743 if (!!info->args.capsarch ^ !!info->args.capsver) {
744 fprintf(stderr, "ARG_CAPS_ARCH and ARG_CAPS_VER must be specified together.\n");
745 return -1;
746 }
747
748 if (info->args.capsarch && info->args.capsver) {
749 bool stripmachinealiases = false;
750 virQEMUCaps *cachedcaps = NULL;
751
752 if (info->args.fakeCapsUsed) {
753 fprintf(stderr, "ARG_QEMU_CAPS can not be combined with ARG_CAPS_ARCH or ARG_CAPS_VER\n");
754 return -1;
755 }
756
757 info->arch = virArchFromString(info->args.capsarch);
758
759 if (STREQ(info->args.capsver, "latest")) {
760 capsfile = g_strdup(virHashLookup(info->conf->capslatest, info->args.capsarch));
761
762 if (!capsfile) {
763 fprintf(stderr, "'latest' caps for '%s' were not found\n", info->args.capsarch);
764 return -1;
765 }
766
767 stripmachinealiases = true;
768 } else {
769 capsfile = g_strdup_printf("%s/caps_%s.%s.xml",
770 TEST_QEMU_CAPS_PATH,
771 info->args.capsver,
772 info->args.capsarch);
773 }
774
775 if (!g_hash_table_lookup_extended(info->conf->capscache, capsfile, NULL, (void **) &cachedcaps)) {
776 if (!(cachedcaps = qemuTestParseCapabilitiesArch(info->arch, capsfile)))
777 return -1;
778
779 g_hash_table_insert(info->conf->capscache, g_strdup(capsfile), cachedcaps);
780 }
781
782 if (!(info->qemuCaps = virQEMUCapsNewCopy(cachedcaps)))
783 return -1;
784
785 if (stripmachinealiases)
786 virQEMUCapsStripMachineAliases(info->qemuCaps);
787
788 info->flags |= FLAG_REAL_CAPS;
789
790 /* provide path to the replies file for schema testing */
791 capsfile[strlen(capsfile) - 3] = '\0';
792 info->schemafile = g_strdup_printf("%sreplies", capsfile);
793 } else {
794 info->qemuCaps = g_steal_pointer(&info->args.fakeCaps);
795 }
796
797 if (info->args.gic != GIC_NONE &&
798 testQemuCapsSetGIC(info->qemuCaps, info->args.gic) < 0)
799 return -1;
800
801 return 0;
802 }
803
804
805 void
testQemuInfoClear(struct testQemuInfo * info)806 testQemuInfoClear(struct testQemuInfo *info)
807 {
808 VIR_FREE(info->infile);
809 VIR_FREE(info->outfile);
810 VIR_FREE(info->schemafile);
811 VIR_FREE(info->errfile);
812 virObjectUnref(info->qemuCaps);
813 g_clear_pointer(&info->args.fakeCaps, virObjectUnref);
814 }
815