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