diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 76b4fac2c4..0a99550afa 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -144,7 +144,7 @@ virBhyveDriverCreateXMLConf(bhyveConnPtr driver) virBhyveDriverDomainDefParserConfig.priv = driver; return virDomainXMLOptionNew(&virBhyveDriverDomainDefParserConfig, &virBhyveDriverPrivateDataCallbacks, - NULL); + NULL, NULL); } virDomainDefParserConfig virBhyveDriverDomainDefParserConfig = { diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c7e20b8ba1..9cd39edf22 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -76,6 +76,9 @@ struct _virDomainXMLOption { /* XML namespace callbacks */ virDomainXMLNamespace ns; + + /* ABI stability callbacks */ + virDomainABIStability abi; }; #define VIR_DOMAIN_DEF_FORMAT_COMMON_FLAGS \ @@ -1050,7 +1053,8 @@ virDomainKeyWrapDefParseXML(virDomainDefPtr def, xmlXPathContextPtr ctxt) virDomainXMLOptionPtr virDomainXMLOptionNew(virDomainDefParserConfigPtr config, virDomainXMLPrivateDataCallbacksPtr priv, - virDomainXMLNamespacePtr xmlns) + virDomainXMLNamespacePtr xmlns, + virDomainABIStabilityPtr abi) { virDomainXMLOptionPtr xmlopt; @@ -1069,6 +1073,9 @@ virDomainXMLOptionNew(virDomainDefParserConfigPtr config, if (xmlns) xmlopt->ns = *xmlns; + if (abi) + xmlopt->abi = *abi; + /* Technically this forbids to use one of Xerox's MAC address prefixes in * our hypervisor drivers. This shouldn't ever be a problem. * @@ -19984,6 +19991,7 @@ virDomainDefVcpuCheckAbiStability(virDomainDefPtr src, bool virDomainDefCheckABIStabilityFlags(virDomainDefPtr src, virDomainDefPtr dst, + virDomainXMLOptionPtr xmlopt, unsigned int flags) { size_t i; @@ -20385,6 +20393,10 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src, !virDomainIOMMUDefCheckABIStability(src->iommu, dst->iommu)) goto error; + if (xmlopt && xmlopt->abi.domain && + !xmlopt->abi.domain(src, dst)) + goto error; + /* Coverity is not very happy with this - all dead_error_condition */ #if !STATIC_ANALYSIS /* This switch statement is here to trigger compiler warning when adding @@ -20444,9 +20456,10 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src, bool virDomainDefCheckABIStability(virDomainDefPtr src, - virDomainDefPtr dst) + virDomainDefPtr dst, + virDomainXMLOptionPtr xmlopt) { - return virDomainDefCheckABIStabilityFlags(src, dst, 0); + return virDomainDefCheckABIStabilityFlags(src, dst, xmlopt, 0); } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 83e0672691..446b117b7c 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -2537,9 +2537,19 @@ struct _virDomainXMLPrivateDataCallbacks { virDomainXMLPrivateDataParseFunc parse; }; +typedef bool (*virDomainABIStabilityDomain)(const virDomainDef *src, + const virDomainDef *dst); + +typedef struct _virDomainABIStability virDomainABIStability; +typedef virDomainABIStability *virDomainABIStabilityPtr; +struct _virDomainABIStability { + virDomainABIStabilityDomain domain; +}; + virDomainXMLOptionPtr virDomainXMLOptionNew(virDomainDefParserConfigPtr config, virDomainXMLPrivateDataCallbacksPtr priv, - virDomainXMLNamespacePtr xmlns); + virDomainXMLNamespacePtr xmlns, + virDomainABIStabilityPtr abi); void virDomainNetGenerateMAC(virDomainXMLOptionPtr xmlopt, virMacAddrPtr mac); @@ -2806,10 +2816,12 @@ virDomainObjPtr virDomainObjParseFile(const char *filename, unsigned int flags); bool virDomainDefCheckABIStability(virDomainDefPtr src, - virDomainDefPtr dst); + virDomainDefPtr dst, + virDomainXMLOptionPtr xmlopt); bool virDomainDefCheckABIStabilityFlags(virDomainDefPtr src, virDomainDefPtr dst, + virDomainXMLOptionPtr xmlopt, unsigned int flags); int virDomainDefAddImplicitDevices(virDomainDefPtr def); diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c index 5daa8d11a7..b6cba5ac38 100644 --- a/src/conf/snapshot_conf.c +++ b/src/conf/snapshot_conf.c @@ -1198,6 +1198,7 @@ virDomainSnapshotRedefinePrep(virDomainPtr domain, virDomainObjPtr vm, virDomainSnapshotDefPtr *defptr, virDomainSnapshotObjPtr *snap, + virDomainXMLOptionPtr xmlopt, bool *update_current, unsigned int flags) { @@ -1286,7 +1287,7 @@ virDomainSnapshotRedefinePrep(virDomainPtr domain, if (other->def->dom) { if (def->dom) { if (!virDomainDefCheckABIStability(other->def->dom, - def->dom)) + def->dom, xmlopt)) goto cleanup; } else { /* Transfer the domain def */ diff --git a/src/conf/snapshot_conf.h b/src/conf/snapshot_conf.h index fcf7a1e824..da904f9460 100644 --- a/src/conf/snapshot_conf.h +++ b/src/conf/snapshot_conf.h @@ -181,6 +181,7 @@ int virDomainSnapshotRedefinePrep(virDomainPtr domain, virDomainObjPtr vm, virDomainSnapshotDefPtr *def, virDomainSnapshotObjPtr *snap, + virDomainXMLOptionPtr xmlopt, bool *update_current, unsigned int flags); diff --git a/src/libxl/libxl_conf.c b/src/libxl/libxl_conf.c index c56b05b38f..886dc629fa 100644 --- a/src/libxl/libxl_conf.c +++ b/src/libxl/libxl_conf.c @@ -2255,5 +2255,5 @@ libxlCreateXMLConf(void) { return virDomainXMLOptionNew(&libxlDomainDefParserConfig, &libxlDomainXMLPrivateDataCallbacks, - NULL); + NULL, NULL); } diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 256cf1dc18..68a501cf16 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -1452,7 +1452,9 @@ libxlDomainDefCheckABIStability(libxlDriverPrivatePtr driver, !(migratableDefDst = virDomainDefCopy(dst, cfg->caps, driver->xmlopt, NULL, true))) goto cleanup; - ret = virDomainDefCheckABIStability(migratableDefSrc, migratableDefDst); + ret = virDomainDefCheckABIStability(migratableDefSrc, + migratableDefDst, + driver->xmlopt); cleanup: virDomainDefFree(migratableDefSrc); diff --git a/src/lxc/lxc_conf.c b/src/lxc/lxc_conf.c index 508b98ba21..ff975decc3 100644 --- a/src/lxc/lxc_conf.c +++ b/src/lxc/lxc_conf.c @@ -215,7 +215,8 @@ lxcDomainXMLConfInit(void) { return virDomainXMLOptionNew(&virLXCDriverDomainDefParserConfig, &virLXCDriverPrivateDataCallbacks, - &virLXCDriverDomainXMLNamespace); + &virLXCDriverDomainXMLNamespace, + NULL); } diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 9c4a196354..8e305a85c0 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -1483,7 +1483,7 @@ static virDrvOpenStatus openvzConnectOpen(virConnectPtr conn, goto cleanup; if (!(driver->xmlopt = virDomainXMLOptionNew(&openvzDomainDefParserConfig, - NULL, NULL))) + NULL, NULL, NULL))) goto cleanup; if (openvzLoadDomains(driver) < 0) diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c index 0cc288f36d..4465ac862d 100644 --- a/src/phyp/phyp_driver.c +++ b/src/phyp/phyp_driver.c @@ -1202,7 +1202,7 @@ phypConnectOpen(virConnectPtr conn, goto failure; if (!(phyp_driver->xmlopt = virDomainXMLOptionNew(&virPhypDriverDomainDefParserConfig, - NULL, NULL))) + NULL, NULL, NULL))) goto failure; conn->privateData = phyp_driver; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7ea8505305..03c55853f1 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -5026,7 +5026,7 @@ virQEMUCapsInitQMPCommandRun(virQEMUCapsInitQMPCommandPtr cmd, goto ignore; } - if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL)) || + if (!(xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL)) || !(cmd->vm = virDomainObjNew(xmlopt))) goto cleanup; diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 19ddf787dc..78f55c0e77 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -909,7 +909,8 @@ virQEMUDriverCreateXMLConf(virQEMUDriverPtr driver) virQEMUDriverDomainDefParserConfig.priv = driver; return virDomainXMLOptionNew(&virQEMUDriverDomainDefParserConfig, &virQEMUDriverPrivateDataCallbacks, - &virQEMUDriverDomainXMLNamespace); + &virQEMUDriverDomainXMLNamespace, + NULL); } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0a85ee9d74..173334dfb9 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5839,6 +5839,7 @@ qemuDomainDefCheckABIStability(virQEMUDriverPtr driver, if (!virDomainDefCheckABIStabilityFlags(migratableDefSrc, migratableDefDst, + driver->xmlopt, check_flags)) goto cleanup; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 14bc6708ae..f0cdea6594 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -6142,7 +6142,7 @@ qemuDomainSaveImageUpdateDef(virQEMUDriverPtr driver, VIR_DOMAIN_XML_MIGRATABLE))) goto cleanup; - if (!virDomainDefCheckABIStability(def, newdef_migr)) { + if (!virDomainDefCheckABIStability(def, newdef_migr, driver->xmlopt)) { virErrorPtr err = virSaveLastError(); /* Due to a bug in older version of external snapshot creation @@ -6151,7 +6151,7 @@ qemuDomainSaveImageUpdateDef(virQEMUDriverPtr driver, * saved XML type, we need to check the ABI compatibility against * the user provided XML if the check against the migratable XML * fails. Snapshots created prior to v1.1.3 have this issue. */ - if (!virDomainDefCheckABIStability(def, newdef)) { + if (!virDomainDefCheckABIStability(def, newdef, driver->xmlopt)) { virSetError(err); virFreeError(err); goto cleanup; @@ -14588,6 +14588,7 @@ qemuDomainSnapshotCreateXML(virDomainPtr domain, if (redefine) { if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap, + driver->xmlopt, &update_current, flags) < 0) goto endjob; } else { diff --git a/src/security/virt-aa-helper.c b/src/security/virt-aa-helper.c index 5f5d1cd710..48201d5b8c 100644 --- a/src/security/virt-aa-helper.c +++ b/src/security/virt-aa-helper.c @@ -667,7 +667,7 @@ get_definition(vahControl * ctl, const char *xmlStr) goto exit; } - if (!(ctl->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL))) { + if (!(ctl->xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL, NULL))) { vah_error(ctl, 0, _("Failed to create XML config object")); goto exit; } diff --git a/src/test/test_driver.c b/src/test/test_driver.c index e5938f5eab..604f09b195 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -414,7 +414,7 @@ testDriverNew(void) goto error; } - if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns)) || + if (!(ret->xmlopt = virDomainXMLOptionNew(NULL, NULL, &ns, NULL)) || !(ret->eventState = virObjectEventStateNew()) || !(ret->ifaces = virInterfaceObjListNew()) || !(ret->domains = virDomainObjListNew()) || @@ -6373,6 +6373,7 @@ testDomainSnapshotCreateXML(virDomainPtr domain, if (redefine) { if (virDomainSnapshotRedefinePrep(domain, vm, &def, &snap, + privconn->xmlopt, &update_current, flags) < 0) goto cleanup; } else { @@ -6648,7 +6649,8 @@ testDomainRevertToSnapshot(virDomainSnapshotPtr snapshot, if (virDomainObjIsActive(vm)) { /* Transitions 5, 6, 8, 9 */ /* Check for ABI compatibility. */ - if (!virDomainDefCheckABIStability(vm->def, config)) { + if (!virDomainDefCheckABIStability(vm->def, config, + privconn->xmlopt)) { virErrorPtr err = virGetLastError(); if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) { diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 03edc897cc..58ab033c80 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -533,7 +533,7 @@ umlStateInitialize(bool privileged, goto out_of_memory; if (!(uml_driver->xmlopt = virDomainXMLOptionNew(¨DriverDomainDefParserConfig, - &privcb, NULL))) + &privcb, NULL, NULL))) goto error; if ((uml_driver->inotifyFD = inotify_init()) < 0) { diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c index d6d363e456..c66939e010 100644 --- a/src/vbox/vbox_common.c +++ b/src/vbox/vbox_common.c @@ -142,7 +142,7 @@ vboxDriverObjNew(void) if (!(driver->caps = vboxCapsInit()) || !(driver->xmlopt = virDomainXMLOptionNew(&vboxDomainDefParserConfig, - NULL, NULL))) + NULL, NULL, NULL))) goto cleanup; return driver; diff --git a/src/vmware/vmware_driver.c b/src/vmware/vmware_driver.c index 6853658334..9e369e67be 100644 --- a/src/vmware/vmware_driver.c +++ b/src/vmware/vmware_driver.c @@ -114,7 +114,7 @@ vmwareDomainXMLConfigInit(void) virDomainXMLPrivateDataCallbacks priv = { .alloc = vmwareDataAllocFunc, .free = vmwareDataFreeFunc }; - return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv, NULL); + return virDomainXMLOptionNew(&vmwareDomainDefParserConfig, &priv, NULL, NULL); } static virDrvOpenStatus diff --git a/src/vmx/vmx.c b/src/vmx/vmx.c index 31af2e9df4..3289a20026 100644 --- a/src/vmx/vmx.c +++ b/src/vmx/vmx.c @@ -591,7 +591,7 @@ virDomainXMLOptionPtr virVMXDomainXMLConfInit(void) { return virDomainXMLOptionNew(&virVMXDomainDefParserConfig, NULL, - &virVMXDomainXMLNamespace); + &virVMXDomainXMLNamespace, NULL); } char * diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index ef7b4531e3..2c021884f1 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -328,7 +328,7 @@ vzDriverObjNew(void) if (!(driver->caps = vzBuildCapabilities()) || !(driver->xmlopt = virDomainXMLOptionNew(&vzDomainDefParserConfig, &vzDomainXMLPrivateDataCallbacksPtr, - NULL)) || + NULL, NULL)) || !(driver->domains = virDomainObjListNew()) || !(driver->domainEventState = virObjectEventStateNew()) || (vzInitVersion(driver) < 0) || diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 4d1408927f..f81ee20ad3 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -401,7 +401,7 @@ virDomainXMLOptionPtr xenDomainXMLConfInit(void) { return virDomainXMLOptionNew(&xenDomainDefParserConfig, - NULL, NULL); + NULL, NULL, NULL); } diff --git a/src/xenapi/xenapi_driver.c b/src/xenapi/xenapi_driver.c index 37d1a6fd9d..380c3a1deb 100644 --- a/src/xenapi/xenapi_driver.c +++ b/src/xenapi/xenapi_driver.c @@ -200,7 +200,7 @@ xenapiConnectOpen(virConnectPtr conn, virConnectAuthPtr auth, } if (!(privP->xmlopt = virDomainXMLOptionNew(&xenapiDomainDefParserConfig, - NULL, NULL))) { + NULL, NULL, NULL))) { xenapiSessionErrorHandler(conn, VIR_ERR_INTERNAL_ERROR, _("Failed to create XML conf object")); goto error; diff --git a/tests/bhyveargv2xmltest.c b/tests/bhyveargv2xmltest.c index 08b2dfd4be..bde7d0e05d 100644 --- a/tests/bhyveargv2xmltest.c +++ b/tests/bhyveargv2xmltest.c @@ -130,7 +130,8 @@ mymain(void) if ((driver.caps = virBhyveCapsBuild()) == NULL) return EXIT_FAILURE; - if ((driver.xmlopt = virDomainXMLOptionNew(NULL, NULL, NULL)) == NULL) + if ((driver.xmlopt = virDomainXMLOptionNew(NULL, NULL, + NULL, NULL)) == NULL) return EXIT_FAILURE; # define DO_TEST_FULL(name, flags) \ diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 0b519a460b..1adbcfef6e 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -95,7 +95,7 @@ static int testCompareXMLToArgvFiles(const char *xmlfile, if (testSanitizeDef(vmdef) < 0) goto fail; - if (!virDomainDefCheckABIStability(vmdef, vmdef)) { + if (!virDomainDefCheckABIStability(vmdef, vmdef, driver.xmlopt)) { VIR_TEST_DEBUG("ABI stability check failed on %s", xmlfile); goto fail; } diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index b3601854be..b7d7cc2abb 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -463,7 +463,7 @@ testCompareXMLToArgv(const void *data) if (virBitmapParse("0-3", &priv->autoNodeset, 4) < 0) goto cleanup; - if (!virDomainDefCheckABIStability(vm->def, vm->def)) { + if (!virDomainDefCheckABIStability(vm->def, vm->def, driver.xmlopt)) { VIR_TEST_DEBUG("ABI stability check failed on %s", xml); goto cleanup; } diff --git a/tests/sexpr2xmltest.c b/tests/sexpr2xmltest.c index 107509b31a..5dfc45d7d3 100644 --- a/tests/sexpr2xmltest.c +++ b/tests/sexpr2xmltest.c @@ -57,7 +57,7 @@ testCompareFiles(const char *xml, const char *sexpr) tty, vncport, caps, xmlopt))) goto fail; - if (!virDomainDefCheckABIStability(def, def)) { + if (!virDomainDefCheckABIStability(def, def, xmlopt)) { fprintf(stderr, "ABI stability check failed on %s", xml); goto fail; } diff --git a/tests/testutils.c b/tests/testutils.c index 817fffa041..4fb2338bb1 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -1136,7 +1136,7 @@ virDomainXMLOptionPtr virTestGenericDomainXMLConfInit(void) { return virDomainXMLOptionNew(&virTestGenericDomainDefParserConfig, &virTestGenericPrivateDataCallbacks, - NULL); + NULL, NULL); } @@ -1169,7 +1169,7 @@ testCompareDomXML2XMLFiles(virCapsPtr caps, virDomainXMLOptionPtr xmlopt, goto out; } - if (!virDomainDefCheckABIStability(def, def)) { + if (!virDomainDefCheckABIStability(def, def, xmlopt)) { VIR_TEST_DEBUG("ABI stability check failed on %s", infile); result = TEST_COMPARE_DOM_XML2XML_RESULT_FAIL_STABILITY; goto out; diff --git a/tests/vmx2xmltest.c b/tests/vmx2xmltest.c index 4eedbac2bc..00385dfa71 100644 --- a/tests/vmx2xmltest.c +++ b/tests/vmx2xmltest.c @@ -81,7 +81,7 @@ testCompareFiles(const char *vmx, const char *xml) if (!(def = virVMXParseConfig(&ctx, xmlopt, caps, vmxData))) goto cleanup; - if (!virDomainDefCheckABIStability(def, def)) { + if (!virDomainDefCheckABIStability(def, def, xmlopt)) { fprintf(stderr, "ABI stability check failed on %s", vmx); goto cleanup; } diff --git a/tests/xlconfigtest.c b/tests/xlconfigtest.c index 05f7c2042b..3fe42988de 100644 --- a/tests/xlconfigtest.c +++ b/tests/xlconfigtest.c @@ -97,7 +97,7 @@ testCompareParseXML(const char *xlcfg, const char *xml, bool replaceVars) goto fail; } - if (!virDomainDefCheckABIStability(def, def)) { + if (!virDomainDefCheckABIStability(def, def, xmlopt)) { fprintf(stderr, "ABI stability check failed on %s", xml); goto fail; } diff --git a/tests/xmconfigtest.c b/tests/xmconfigtest.c index aa3845bf00..345223ffe4 100644 --- a/tests/xmconfigtest.c +++ b/tests/xmconfigtest.c @@ -67,7 +67,7 @@ testCompareParseXML(const char *xmcfg, const char *xml) VIR_DOMAIN_DEF_PARSE_INACTIVE))) goto fail; - if (!virDomainDefCheckABIStability(def, def)) { + if (!virDomainDefCheckABIStability(def, def, xmlopt)) { fprintf(stderr, "ABI stability check failed on %s", xml); goto fail; } diff --git a/tests/xml2sexprtest.c b/tests/xml2sexprtest.c index fddccf0296..0ba8a765bf 100644 --- a/tests/xml2sexprtest.c +++ b/tests/xml2sexprtest.c @@ -31,7 +31,7 @@ testCompareFiles(const char *xml, const char *sexpr) VIR_DOMAIN_DEF_PARSE_INACTIVE))) goto fail; - if (!virDomainDefCheckABIStability(def, def)) { + if (!virDomainDefCheckABIStability(def, def, xmlopt)) { fprintf(stderr, "ABI stability check failed on %s", xml); goto fail; } diff --git a/tests/xml2vmxtest.c b/tests/xml2vmxtest.c index 71c4cb9dc8..13f53e7d2d 100644 --- a/tests/xml2vmxtest.c +++ b/tests/xml2vmxtest.c @@ -82,7 +82,7 @@ testCompareFiles(const char *xml, const char *vmx, int virtualHW_version) if (def == NULL) goto failure; - if (!virDomainDefCheckABIStability(def, def)) { + if (!virDomainDefCheckABIStability(def, def, xmlopt)) { fprintf(stderr, "ABI stability check failed on %s", xml); goto failure; }