virDomainDefParseXML(xmlDocPtr xml,
                     xmlXPathContextPtr ctxt,
                     virDomainXMLOptionPtr xmlopt,
                     unsigned int flags)
{
    xmlNodePtr node = NULL;
    size_t i, j;
    int n, gic_version;
    long id = -1;
    virDomainDefPtr def;
    bool uuid_generated = false;
    bool usb_none = false;
    bool usb_other = false;
    bool usb_master = false;
    g_autofree xmlNodePtr *nodes = NULL;
    g_autofree char *tmp = NULL;

    if (flags & VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA) {
        g_autofree char *schema = NULL;

        schema = virFileFindResource("domain.rng",
                                     abs_top_srcdir "/docs/schemas",
                                     PKGDATADIR "/schemas");
        if (!schema)
            return NULL;
        if (virXMLValidateAgainstSchema(schema, xml) < 0)
            return NULL;
    }

    if (!(def = virDomainDefNew()))
        return NULL;

    if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))
        if (virXPathLong("string(./@id)", ctxt, &id) < 0)
            id = -1;
    def->id = (int)id;

    if (virDomainDefParseCaps(def, ctxt, xmlopt) < 0)
        goto error;

    /* Extract domain name */
    if (!(def->name = virXPathString("string(./name[1])", ctxt))) {
        virReportError(VIR_ERR_NO_NAME, NULL);
        goto error;
    }

    /* Extract domain uuid. If both uuid and sysinfo/system/entry/uuid
     * exist, they must match; and if only the latter exists, it can
     * also serve as the uuid. */
    tmp = virXPathString("string(./uuid[1])", ctxt);
    if (!tmp) {
        if (virUUIDGenerate(def->uuid) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to generate UUID"));
            goto error;
        }
        uuid_generated = true;
    } else {
        if (virUUIDParse(tmp, def->uuid) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("malformed uuid element"));
            goto error;
        }
        VIR_FREE(tmp);
    }

    /* Extract domain genid - a genid can either be provided or generated */
    if ((n = virXPathNodeSet("./genid", ctxt, &nodes)) < 0)
        goto error;

    if (n > 0) {
        if (n != 1) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("element 'genid' can only appear once"));
            goto error;
        }
        def->genidRequested = true;
        if (!(tmp = virXPathString("string(./genid)", ctxt))) {
            if (virUUIDGenerate(def->genid) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("Failed to generate genid"));
                goto error;
            }
            def->genidGenerated = true;
        } else {
            if (virUUIDParse(tmp, def->genid) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("malformed genid element"));
                goto error;
            }
            VIR_FREE(tmp);
        }
    }
    VIR_FREE(nodes);

    /* Extract short description of domain (title) */
    def->title = virXPathString("string(./title[1])", ctxt);
    if (def->title && strchr(def->title, '\n')) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Domain title can't contain newlines"));
        goto error;
    }

    /* Extract documentation if present */
    def->description = virXPathString("string(./description[1])", ctxt);

    /* analysis of security label, done early even though we format it
     * late, so devices can refer to this for defaults */
    if (!(flags & VIR_DOMAIN_DEF_PARSE_SKIP_SECLABEL)) {
        if (virSecurityLabelDefsParseXML(def, ctxt, xmlopt, flags) == -1)
            goto error;
    }

    /* Extract domain memory */
    if (virDomainParseMemory("./memory[1]", NULL, ctxt,
                             &def->mem.total_memory, false, true) < 0)
        goto error;

    if (virDomainParseMemory("./currentMemory[1]", NULL, ctxt,
                             &def->mem.cur_balloon, false, true) < 0)
        goto error;

    if (virDomainParseMemory("./maxMemory[1]", NULL, ctxt,
                             &def->mem.max_memory, false, false) < 0)
        goto error;

    if (virXPathUInt("string(./maxMemory[1]/@slots)", ctxt, &def->mem.memory_slots) == -2) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("Failed to parse memory slot count"));
        goto error;
    }

    /* and info about it */
    if ((tmp = virXPathString("string(./memory[1]/@dumpCore)", ctxt)) &&
        (def->mem.dump_core = virTristateSwitchTypeFromString(tmp)) <= 0) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Invalid memory core dump attribute value '%s'"), tmp);
        goto error;
    }
    VIR_FREE(tmp);

    tmp = virXPathString("string(./memoryBacking/source/@type)", ctxt);
    if (tmp) {
        if ((def->mem.source = virDomainMemorySourceTypeFromString(tmp)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown memoryBacking/source/type '%s'"), tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    tmp = virXPathString("string(./memoryBacking/access/@mode)", ctxt);
    if (tmp) {
        if ((def->mem.access = virDomainMemoryAccessTypeFromString(tmp)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown memoryBacking/access/mode '%s'"), tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    tmp = virXPathString("string(./memoryBacking/allocation/@mode)", ctxt);
    if (tmp) {
        if ((def->mem.allocation = virDomainMemoryAllocationTypeFromString(tmp)) <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown memoryBacking/allocation/mode '%s'"), tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    if (virXPathNode("./memoryBacking/hugepages", ctxt)) {
        /* hugepages will be used */
        if ((n = virXPathNodeSet("./memoryBacking/hugepages/page", ctxt, &nodes)) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("cannot extract hugepages nodes"));
            goto error;
        }

        if (n) {
            if (VIR_ALLOC_N(def->mem.hugepages, n) < 0)
                goto error;

            for (i = 0; i < n; i++) {
                if (virDomainHugepagesParseXML(nodes[i], ctxt,
                                               &def->mem.hugepages[i]) < 0)
                    goto error;
                def->mem.nhugepages++;
            }

            VIR_FREE(nodes);
        } else {
            /* no hugepage pages */
            if (VIR_ALLOC(def->mem.hugepages) < 0)
                goto error;

            def->mem.nhugepages = 1;
        }
    }

    if ((node = virXPathNode("./memoryBacking/nosharepages", ctxt)))
        def->mem.nosharepages = true;

    if (virXPathBoolean("boolean(./memoryBacking/locked)", ctxt))
        def->mem.locked = true;

    if (virXPathBoolean("boolean(./memoryBacking/discard)", ctxt))
        def->mem.discard = VIR_TRISTATE_BOOL_YES;

    /* Extract blkio cgroup tunables */
    if (virXPathUInt("string(./blkiotune/weight)", ctxt,
                     &def->blkio.weight) < 0)
        def->blkio.weight = 0;

    if ((n = virXPathNodeSet("./blkiotune/device", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract blkiotune nodes"));
        goto error;
    }
    if (n && VIR_ALLOC_N(def->blkio.devices, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        if (virDomainBlkioDeviceParseXML(nodes[i],
                                         &def->blkio.devices[i]) < 0)
            goto error;
        def->blkio.ndevices++;
        for (j = 0; j < i; j++) {
            if (STREQ(def->blkio.devices[j].path,
                      def->blkio.devices[i].path)) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("duplicate blkio device path '%s'"),
                               def->blkio.devices[i].path);
                goto error;
            }
        }
    }
    VIR_FREE(nodes);

    /* Extract other memory tunables */
    if (virDomainParseMemoryLimit("./memtune/hard_limit[1]", NULL, ctxt,
                                  &def->mem.hard_limit) < 0)
        goto error;

    if (virDomainParseMemoryLimit("./memtune/soft_limit[1]", NULL, ctxt,
                                  &def->mem.soft_limit) < 0)
        goto error;

    if (virDomainParseMemory("./memtune/min_guarantee[1]", NULL, ctxt,
                             &def->mem.min_guarantee, false, false) < 0)
        goto error;

    if (virDomainParseMemoryLimit("./memtune/swap_hard_limit[1]", NULL, ctxt,
                                  &def->mem.swap_hard_limit) < 0)
        goto error;

    if (virDomainVcpuParse(def, ctxt, xmlopt) < 0)
        goto error;

    if (virDomainDefParseIOThreads(def, ctxt) < 0)
        goto error;

    /* Extract cpu tunables. */
    if ((n = virXPathULongLong("string(./cputune/shares[1])", ctxt,
                               &def->cputune.shares)) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune shares value"));
        goto error;
    } else if (n == 0) {
        def->cputune.sharesSpecified = true;
    }

    if (virXPathULongLong("string(./cputune/period[1])", ctxt,
                          &def->cputune.period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune period value"));
        goto error;
    }

    if (virXPathLongLong("string(./cputune/quota[1])", ctxt,
                         &def->cputune.quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune quota value"));
        goto error;
    }

    if (virXPathULongLong("string(./cputune/global_period[1])", ctxt,
                          &def->cputune.global_period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune global period value"));
        goto error;
    }

    if (virXPathLongLong("string(./cputune/global_quota[1])", ctxt,
                         &def->cputune.global_quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune global quota value"));
        goto error;
    }

    if (virXPathULongLong("string(./cputune/emulator_period[1])", ctxt,
                          &def->cputune.emulator_period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator period value"));
        goto error;
    }

    if (virXPathLongLong("string(./cputune/emulator_quota[1])", ctxt,
                         &def->cputune.emulator_quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune emulator quota value"));
        goto error;
    }


    if (virXPathULongLong("string(./cputune/iothread_period[1])", ctxt,
                          &def->cputune.iothread_period) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune iothread period value"));
        goto error;
    }

    if (virXPathLongLong("string(./cputune/iothread_quota[1])", ctxt,
                         &def->cputune.iothread_quota) < -1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("can't parse cputune iothread quota value"));
        goto error;
    }

    if ((n = virXPathNodeSet("./cputune/vcpupin", ctxt, &nodes)) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        if (virDomainVcpuPinDefParseXML(def, nodes[i]))
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./cputune/emulatorpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract emulatorpin nodes"));
        goto error;
    }

    if (n) {
        if (n > 1) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("only one emulatorpin is supported"));
            VIR_FREE(nodes);
            goto error;
        }

        if (!(def->cputune.emulatorpin = virDomainEmulatorPinDefParseXML(nodes[0])))
            goto error;
    }
    VIR_FREE(nodes);


    if ((n = virXPathNodeSet("./cputune/iothreadpin", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract iothreadpin nodes"));
        goto error;
    }

    for (i = 0; i < n; i++) {
        if (virDomainIOThreadPinDefParseXML(nodes[i], def) < 0)
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./cputune/vcpusched", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract vcpusched nodes"));
        goto error;
    }

    for (i = 0; i < n; i++) {
        if (virDomainVcpuThreadSchedParse(nodes[i], def) < 0)
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./cputune/iothreadsched", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract iothreadsched nodes"));
        goto error;
    }

    for (i = 0; i < n; i++) {
        if (virDomainIOThreadSchedParse(nodes[i], def) < 0)
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./cputune/emulatorsched", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract emulatorsched nodes"));
        goto error;
    }

    if (n) {
        if (n > 1) {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("only one emulatorsched is supported"));
            VIR_FREE(nodes);
            goto error;
        }

        if (virDomainEmulatorSchedParse(nodes[0], def) < 0)
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./cputune/cachetune", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract cachetune nodes"));
        goto error;
    }

    for (i = 0; i < n; i++) {
        if (virDomainCachetuneDefParse(def, ctxt, nodes[i], flags) < 0)
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./cputune/memorytune", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("cannot extract memorytune nodes"));
        goto error;
    }

    for (i = 0; i < n; i++) {
        if (virDomainMemorytuneDefParse(def, ctxt, nodes[i], flags) < 0)
            goto error;
    }
    VIR_FREE(nodes);

    if (virCPUDefParseXML(ctxt, "./cpu[1]", VIR_CPU_TYPE_GUEST, &def->cpu) < 0)
        goto error;

    if (virDomainNumaDefCPUParseXML(def->numa, ctxt) < 0)
        goto error;

    if (virDomainNumaGetCPUCountTotal(def->numa) > virDomainDefGetVcpusMax(def)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Number of CPUs in <numa> exceeds the"
                         " <vcpu> count"));
        goto error;
    }

    if (virDomainNumaGetMaxCPUID(def->numa) >= virDomainDefGetVcpusMax(def)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("CPU IDs in <numa> exceed the <vcpu> count"));
        goto error;
    }

    if (virDomainNumatuneParseXML(def->numa,
                                  def->placement_mode ==
                                  VIR_DOMAIN_CPU_PLACEMENT_MODE_STATIC,
                                  ctxt) < 0)
        goto error;

    if (virDomainNumatuneHasPlacementAuto(def->numa) &&
        !def->cpumask && !virDomainDefHasVcpuPin(def) &&
        !def->cputune.emulatorpin &&
        !virDomainIOThreadIDArrayHasPin(def))
        def->placement_mode = VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO;

    if ((n = virXPathNodeSet("./resource", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract resource nodes"));
        goto error;
    }

    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only one resource element is supported"));
        goto error;
    }

    if (n &&
        !(def->resource = virDomainResourceDefParse(nodes[0], ctxt)))
        goto error;
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./features/*", ctxt, &nodes)) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        int val = virDomainFeatureTypeFromString((const char *)nodes[i]->name);
        if (val < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unexpected feature '%s'"), nodes[i]->name);
            goto error;
        }

        switch ((virDomainFeature) val) {
        case VIR_DOMAIN_FEATURE_APIC:
            if ((tmp = virXPathString("string(./features/apic/@eoi)", ctxt))) {
                int eoi;
                if ((eoi = virTristateSwitchTypeFromString(tmp)) <= 0) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown value for attribute eoi: '%s'"),
                                   tmp);
                    goto error;
                }
                def->apic_eoi = eoi;
                VIR_FREE(tmp);
            }
            G_GNUC_FALLTHROUGH;
        case VIR_DOMAIN_FEATURE_ACPI:
        case VIR_DOMAIN_FEATURE_PAE:
        case VIR_DOMAIN_FEATURE_VIRIDIAN:
        case VIR_DOMAIN_FEATURE_PRIVNET:
        case VIR_DOMAIN_FEATURE_HYPERV:
        case VIR_DOMAIN_FEATURE_KVM:
        case VIR_DOMAIN_FEATURE_MSRS:
            def->features[val] = VIR_TRISTATE_SWITCH_ON;
            break;

        case VIR_DOMAIN_FEATURE_CAPABILITIES:
            if ((tmp = virXMLPropString(nodes[i], "policy"))) {
                if ((def->features[val] = virDomainCapabilitiesPolicyTypeFromString(tmp)) == -1) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown policy attribute '%s' of feature '%s'"),
                                   tmp, virDomainFeatureTypeToString(val));
                    goto error;
                }
                VIR_FREE(tmp);
            } else {
                def->features[val] = VIR_TRISTATE_SWITCH_ABSENT;
            }
            break;

        case VIR_DOMAIN_FEATURE_VMCOREINFO:
        case VIR_DOMAIN_FEATURE_HAP:
        case VIR_DOMAIN_FEATURE_PMU:
        case VIR_DOMAIN_FEATURE_PVSPINLOCK:
        case VIR_DOMAIN_FEATURE_VMPORT:
        case VIR_DOMAIN_FEATURE_SMM:
            if ((tmp = virXMLPropString(nodes[i], "state"))) {
                if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("unknown state attribute '%s' of feature '%s'"),
                                   tmp, virDomainFeatureTypeToString(val));
                    goto error;
                }
                VIR_FREE(tmp);
            } else {
                def->features[val] = VIR_TRISTATE_SWITCH_ON;
            }
            break;

        case VIR_DOMAIN_FEATURE_GIC:
            if ((tmp = virXMLPropString(nodes[i], "version"))) {
                gic_version = virGICVersionTypeFromString(tmp);
                if (gic_version < 0 || gic_version == VIR_GIC_VERSION_NONE) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("malformed gic version: %s"), tmp);
                    goto error;
                }
                def->gic_version = gic_version;
                VIR_FREE(tmp);
            }
            def->features[val] = VIR_TRISTATE_SWITCH_ON;
            break;

        case VIR_DOMAIN_FEATURE_IOAPIC:
            tmp = virXMLPropString(nodes[i], "driver");
            if (tmp) {
                int value = virDomainIOAPICTypeFromString(tmp);
                if (value < 0 || value == VIR_DOMAIN_IOAPIC_NONE) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("Unknown driver mode: %s"),
                                   tmp);
                    goto error;
                }
                def->features[val] = value;
                VIR_FREE(tmp);
            }
            break;

        case VIR_DOMAIN_FEATURE_HPT:
            tmp = virXMLPropString(nodes[i], "resizing");
            if (tmp) {
                int value = virDomainHPTResizingTypeFromString(tmp);
                if (value < 0 || value == VIR_DOMAIN_HPT_RESIZING_NONE) {
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("Unknown HPT resizing setting: %s"),
                                   tmp);
                    goto error;
                }
                def->hpt_resizing = (virDomainHPTResizing) value;
                VIR_FREE(tmp);
            }

            if (virDomainParseScaledValue("./features/hpt/maxpagesize",
                                          NULL,
                                          ctxt,
                                          &def->hpt_maxpagesize,
                                          1024,
                                          ULLONG_MAX,
                                          false) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               "%s",
                               _("Unable to parse HPT maxpagesize setting"));
                goto error;
            }
            def->hpt_maxpagesize = VIR_DIV_UP(def->hpt_maxpagesize, 1024);

            if (def->hpt_resizing != VIR_DOMAIN_HPT_RESIZING_NONE ||
                def->hpt_maxpagesize > 0) {
                def->features[val] = VIR_TRISTATE_SWITCH_ON;
            }
            break;

        case VIR_DOMAIN_FEATURE_HTM:
        case VIR_DOMAIN_FEATURE_NESTED_HV:
        case VIR_DOMAIN_FEATURE_CCF_ASSIST:
            if (!(tmp = virXMLPropString(nodes[i], "state"))) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("missing state attribute '%s' of feature '%s'"),
                               tmp, virDomainFeatureTypeToString(val));
                goto error;
            }
            if ((def->features[val] = virTristateSwitchTypeFromString(tmp)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown state attribute '%s' of feature '%s'"),
                               tmp, virDomainFeatureTypeToString(val));
                goto error;
            }
            VIR_FREE(tmp);
            break;

        /* coverity[dead_error_begin] */
        case VIR_DOMAIN_FEATURE_LAST:
            break;
        }
    }
    VIR_FREE(nodes);

    if (def->features[VIR_DOMAIN_FEATURE_HYPERV] == VIR_TRISTATE_SWITCH_ON) {
        int feature;
        int value;
        node = ctxt->node;
        if ((n = virXPathNodeSet("./features/hyperv/*", ctxt, &nodes)) < 0)
            goto error;

        for (i = 0; i < n; i++) {
            feature = virDomainHypervTypeFromString((const char *)nodes[i]->name);
            if (feature < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported HyperV Enlightenment feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            ctxt->node = nodes[i];

            if (!(tmp = virXMLPropString(nodes[i], "state"))) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("missing 'state' attribute for "
                                 "HyperV Enlightenment feature '%s'"),
                               nodes[i]->name);
                goto error;
            }

            if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("invalid value of state argument "
                                 "for HyperV Enlightenment feature '%s'"),
                               nodes[i]->name);
                goto error;
            }

            VIR_FREE(tmp);
            def->hyperv_features[feature] = value;

            switch ((virDomainHyperv) feature) {
            case VIR_DOMAIN_HYPERV_RELAXED:
            case VIR_DOMAIN_HYPERV_VAPIC:
            case VIR_DOMAIN_HYPERV_VPINDEX:
            case VIR_DOMAIN_HYPERV_RUNTIME:
            case VIR_DOMAIN_HYPERV_SYNIC:
            case VIR_DOMAIN_HYPERV_STIMER:
            case VIR_DOMAIN_HYPERV_RESET:
            case VIR_DOMAIN_HYPERV_FREQUENCIES:
            case VIR_DOMAIN_HYPERV_REENLIGHTENMENT:
            case VIR_DOMAIN_HYPERV_TLBFLUSH:
            case VIR_DOMAIN_HYPERV_IPI:
            case VIR_DOMAIN_HYPERV_EVMCS:
                break;

            case VIR_DOMAIN_HYPERV_SPINLOCKS:
                if (value != VIR_TRISTATE_SWITCH_ON)
                    break;

                if (virXPathUInt("string(./@retries)", ctxt,
                             &def->hyperv_spinlocks) < 0) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("invalid HyperV spinlock retry count"));
                    goto error;
                }

                if (def->hyperv_spinlocks < 0xFFF) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("HyperV spinlock retry count must be "
                                     "at least 4095"));
                    goto error;
                }
                break;

            case VIR_DOMAIN_HYPERV_VENDOR_ID:
                if (value != VIR_TRISTATE_SWITCH_ON)
                    break;

                if (!(def->hyperv_vendor_id = virXMLPropString(nodes[i],
                                                               "value"))) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("missing 'value' attribute for "
                                     "HyperV feature 'vendor_id'"));
                    goto error;
                }

                if (strlen(def->hyperv_vendor_id) > VIR_DOMAIN_HYPERV_VENDOR_ID_MAX) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("HyperV vendor_id value must not be more "
                                     "than %d characters."),
                                   VIR_DOMAIN_HYPERV_VENDOR_ID_MAX);
                    goto error;
                }

                /* ensure that the string can be passed to qemu */
                if (strchr(def->hyperv_vendor_id, ',')) {
                    virReportError(VIR_ERR_XML_ERROR, "%s",
                                   _("HyperV vendor_id value is invalid"));
                    goto error;
                }

            /* coverity[dead_error_begin] */
            case VIR_DOMAIN_HYPERV_LAST:
                break;
            }
        }
        VIR_FREE(nodes);
        ctxt->node = node;
    }

    if (def->features[VIR_DOMAIN_HYPERV_STIMER] == VIR_TRISTATE_SWITCH_ON) {
        int value;
        if ((n = virXPathNodeSet("./features/hyperv/stimer/*", ctxt, &nodes)) < 0)
            goto error;

        for (i = 0; i < n; i++) {
            if (STRNEQ((const char *)nodes[i]->name, "direct")) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported Hyper-V stimer feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            if (!(tmp = virXMLPropString(nodes[i], "state"))) {
                virReportError(VIR_ERR_XML_ERROR,
                               _("missing 'state' attribute for "
                                 "Hyper-V stimer '%s' feature"), "direct");
                        goto error;
            }

            if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("invalid value of state argument "
                                 "for Hyper-V stimer '%s' feature"), "direct");
                goto error;
            }

            VIR_FREE(tmp);
            def->hyperv_stimer_direct = value;
        }
        VIR_FREE(nodes);
    }

    if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) {
        int feature;
        int value;
        if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0)
            goto error;

        for (i = 0; i < n; i++) {
            feature = virDomainKVMTypeFromString((const char *)nodes[i]->name);
            if (feature < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported KVM feature: %s"),
                               nodes[i]->name);
                goto error;
            }

            switch ((virDomainKVM) feature) {
                case VIR_DOMAIN_KVM_HIDDEN:
                case VIR_DOMAIN_KVM_DEDICATED:
                    if (!(tmp = virXMLPropString(nodes[i], "state"))) {
                        virReportError(VIR_ERR_XML_ERROR,
                                       _("missing 'state' attribute for "
                                         "KVM feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    if ((value = virTristateSwitchTypeFromString(tmp)) < 0) {
                        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                       _("invalid value of state argument "
                                         "for KVM feature '%s'"),
                                       nodes[i]->name);
                        goto error;
                    }

                    VIR_FREE(tmp);
                    def->kvm_features[feature] = value;
                    break;

                /* coverity[dead_error_begin] */
                case VIR_DOMAIN_KVM_LAST:
                    break;
            }
        }
        VIR_FREE(nodes);
    }

    if (def->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) {
        int rv = virDomainParseScaledValue("string(./features/smm/tseg)",
                                           "string(./features/smm/tseg/@unit)",
                                           ctxt,
                                           &def->tseg_size,
                                           1024 * 1024, /* Defaults to mebibytes */
                                           ULLONG_MAX,
                                           false);
        if (rv < 0)
            goto error;
        def->tseg_specified = rv;
    }

    if (def->features[VIR_DOMAIN_FEATURE_MSRS] == VIR_TRISTATE_SWITCH_ON) {
        if ((node = virXPathNode("./features/msrs", ctxt)) == NULL)
            goto error;

        if (!(tmp = virXMLPropString(node, "unknown"))) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("missing 'unknown' attribute for feature '%s'"),
                           virDomainFeatureTypeToString(VIR_DOMAIN_FEATURE_MSRS));
            goto error;
        }

        if ((def->msrs_features[VIR_DOMAIN_MSRS_UNKNOWN] = virDomainMsrsUnknownTypeFromString(tmp)) < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown 'unknown' value '%s'"),
                           tmp);
            goto error;
        }
        VIR_FREE(tmp);
    }

    if ((n = virXPathNodeSet("./features/capabilities/*", ctxt, &nodes)) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        int val = virDomainProcessCapsFeatureTypeFromString((const char *)nodes[i]->name);
        if (val < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unexpected capability feature '%s'"), nodes[i]->name);
            goto error;
        }

        if ((tmp = virXMLPropString(nodes[i], "state"))) {
            if ((def->caps_features[val] = virTristateSwitchTypeFromString(tmp)) == -1) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown state attribute '%s' of feature capability '%s'"),
                               tmp, virDomainProcessCapsFeatureTypeToString(val));
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->caps_features[val] = VIR_TRISTATE_SWITCH_ON;
        }
    }
    VIR_FREE(nodes);

    if (virDomainEventActionParseXML(ctxt, "on_reboot",
                                     "string(./on_reboot[1])",
                                     &def->onReboot,
                                     VIR_DOMAIN_LIFECYCLE_ACTION_RESTART,
                                     virDomainLifecycleActionTypeFromString) < 0)
        goto error;

    if (virDomainEventActionParseXML(ctxt, "on_poweroff",
                                     "string(./on_poweroff[1])",
                                     &def->onPoweroff,
                                     VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY,
                                     virDomainLifecycleActionTypeFromString) < 0)
        goto error;

    if (virDomainEventActionParseXML(ctxt, "on_crash",
                                     "string(./on_crash[1])",
                                     &def->onCrash,
                                     VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY,
                                     virDomainLifecycleActionTypeFromString) < 0)
        goto error;

    if (virDomainEventActionParseXML(ctxt, "on_lockfailure",
                                     "string(./on_lockfailure[1])",
                                     &def->onLockFailure,
                                     VIR_DOMAIN_LOCK_FAILURE_DEFAULT,
                                     virDomainLockFailureTypeFromString) < 0)
        goto error;

    if (virDomainPMStateParseXML(ctxt,
                                 "string(./pm/suspend-to-mem/@enabled)",
                                 &def->pm.s3) < 0)
        goto error;

    if (virDomainPMStateParseXML(ctxt,
                                 "string(./pm/suspend-to-disk/@enabled)",
                                 &def->pm.s4) < 0)
        goto error;

    if (virDomainPerfDefParseXML(def, ctxt) < 0)
        goto error;

    if ((tmp = virXPathString("string(./clock/@offset)", ctxt)) &&
        (def->clock.offset = virDomainClockOffsetTypeFromString(tmp)) < 0) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unknown clock offset '%s'"), tmp);
        goto error;
    }
    VIR_FREE(tmp);

    switch (def->clock.offset) {
    case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
    case VIR_DOMAIN_CLOCK_OFFSET_UTC:
        tmp = virXPathString("string(./clock/@adjustment)", ctxt);
        if (tmp) {
            if (STREQ(tmp, "reset")) {
                def->clock.data.utc_reset = true;
            } else {
                if (virStrToLong_ll(tmp, NULL, 10,
                                    &def->clock.data.variable.adjustment) < 0) {
                    virReportError(VIR_ERR_XML_ERROR,
                                   _("unknown clock adjustment '%s'"),
                                   tmp);
                    goto error;
                }
                switch (def->clock.offset) {
                case VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME:
                    def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_LOCALTIME;
                    break;
                case VIR_DOMAIN_CLOCK_OFFSET_UTC:
                    def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
                    break;
                }
                def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_VARIABLE;
            }
            VIR_FREE(tmp);
        } else {
            def->clock.data.utc_reset = false;
        }
        break;

    case VIR_DOMAIN_CLOCK_OFFSET_VARIABLE:
        if (virXPathLongLong("number(./clock/@adjustment)", ctxt,
                             &def->clock.data.variable.adjustment) < 0)
            def->clock.data.variable.adjustment = 0;
        if (virXPathLongLong("number(./clock/@adjustment0)", ctxt,
                             &def->clock.data.variable.adjustment0) < 0)
            def->clock.data.variable.adjustment0 = 0;
        tmp = virXPathString("string(./clock/@basis)", ctxt);
        if (tmp) {
            if ((def->clock.data.variable.basis = virDomainClockBasisTypeFromString(tmp)) < 0) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown clock basis '%s'"), tmp);
                goto error;
            }
            VIR_FREE(tmp);
        } else {
            def->clock.data.variable.basis = VIR_DOMAIN_CLOCK_BASIS_UTC;
        }
        break;

    case VIR_DOMAIN_CLOCK_OFFSET_TIMEZONE:
        def->clock.data.timezone = virXPathString("string(./clock/@timezone)", ctxt);
        if (!def->clock.data.timezone) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("missing 'timezone' attribute for clock with offset='timezone'"));
            goto error;
        }
        break;
    }

    if ((n = virXPathNodeSet("./clock/timer", ctxt, &nodes)) < 0)
        goto error;

    if (n && VIR_ALLOC_N(def->clock.timers, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainTimerDefPtr timer = virDomainTimerDefParseXML(nodes[i],
                                                               ctxt);
        if (!timer)
            goto error;

        def->clock.timers[def->clock.ntimers++] = timer;
    }
    VIR_FREE(nodes);

    if (virDomainDefParseBootOptions(def, ctxt) < 0)
        goto error;

    /* analysis of the disk devices */
    if ((n = virXPathNodeSet("./devices/disk", ctxt, &nodes)) < 0)
        goto error;

    if (n && VIR_ALLOC_N(def->disks, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainDiskDefPtr disk = virDomainDiskDefParseXML(xmlopt,
                                                            nodes[i],
                                                            ctxt,
                                                            flags);
        if (!disk)
            goto error;

        virDomainDiskInsertPreAlloced(def, disk);
    }
    VIR_FREE(nodes);

    /* analysis of the controller devices */
    if ((n = virXPathNodeSet("./devices/controller", ctxt, &nodes)) < 0)
        goto error;

    if (n && VIR_ALLOC_N(def->controllers, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainControllerDefPtr controller = virDomainControllerDefParseXML(xmlopt,
                                                                              nodes[i],
                                                                              ctxt,
                                                                              flags);

        if (!controller)
            goto error;

        /* sanitize handling of "none" usb controller */
        if (controller->type == VIR_DOMAIN_CONTROLLER_TYPE_USB) {
            if (controller->model == VIR_DOMAIN_CONTROLLER_MODEL_USB_NONE) {
                if (usb_other || usb_none) {
                    virDomainControllerDefFree(controller);
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("Can't add another USB controller: "
                                     "USB is disabled for this domain"));
                    goto error;
                }
                usb_none = true;
            } else {
                if (usb_none) {
                    virDomainControllerDefFree(controller);
                    virReportError(VIR_ERR_XML_DETAIL, "%s",
                                   _("Can't add another USB controller: "
                                     "USB is disabled for this domain"));
                    goto error;
                }
                usb_other = true;
            }

            if (controller->info.mastertype == VIR_DOMAIN_CONTROLLER_MASTER_NONE)
                usb_master = true;
        }

        virDomainControllerInsertPreAlloced(def, controller);
    }
    VIR_FREE(nodes);

    if (usb_other && !usb_master) {
        virReportError(VIR_ERR_XML_DETAIL, "%s",
                       _("No master USB controller specified"));
        goto error;
    }

    /* analysis of the resource leases */
    if ((n = virXPathNodeSet("./devices/lease", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract device leases"));
        goto error;
    }
    if (n && VIR_ALLOC_N(def->leases, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainLeaseDefPtr lease = virDomainLeaseDefParseXML(nodes[i]);
        if (!lease)
            goto error;

        def->leases[def->nleases++] = lease;
    }
    VIR_FREE(nodes);

    /* analysis of the filesystems */
    if ((n = virXPathNodeSet("./devices/filesystem", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->fss, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainFSDefPtr fs = virDomainFSDefParseXML(xmlopt,
                                                      nodes[i],
                                                      ctxt,
                                                      flags);
        if (!fs)
            goto error;

        def->fss[def->nfss++] = fs;
    }
    VIR_FREE(nodes);

    /* analysis of the network devices */
    if ((n = virXPathNodeSet("./devices/interface", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->nets, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainNetDefPtr net = virDomainNetDefParseXML(xmlopt,
                                                         nodes[i],
                                                         ctxt,
                                                         flags);
        if (!net)
            goto error;

        def->nets[def->nnets++] = net;

        /* <interface type='hostdev'> (and <interface type='net'>
         * where the actual network type is already known to be
         * hostdev) must also be in the hostdevs array.
         */
        if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
            virDomainHostdevInsert(def, virDomainNetGetActualHostdev(net)) < 0) {
            goto error;
        }
    }
    VIR_FREE(nodes);


    /* analysis of the smartcard devices */
    if ((n = virXPathNodeSet("./devices/smartcard", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->smartcards, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainSmartcardDefPtr card = virDomainSmartcardDefParseXML(xmlopt,
                                                                      nodes[i],
                                                                      ctxt,
                                                                      flags);
        if (!card)
            goto error;

        def->smartcards[def->nsmartcards++] = card;
    }
    VIR_FREE(nodes);


    /* analysis of the character devices */
    if ((n = virXPathNodeSet("./devices/parallel", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->parallels, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt,
                                                         ctxt,
                                                         nodes[i],
                                                         flags);
        if (!chr)
            goto error;

        if (chr->target.port == -1) {
            int maxport = -1;
            for (j = 0; j < i; j++) {
                if (def->parallels[j]->target.port > maxport)
                    maxport = def->parallels[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
        def->parallels[def->nparallels++] = chr;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./devices/serial", ctxt, &nodes)) < 0)
        goto error;

    if (n && VIR_ALLOC_N(def->serials, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt,
                                                         ctxt,
                                                         nodes[i],
                                                         flags);
        if (!chr)
            goto error;

        if (chr->target.port == -1) {
            int maxport = -1;
            for (j = 0; j < i; j++) {
                if (def->serials[j]->target.port > maxport)
                    maxport = def->serials[j]->target.port;
            }
            chr->target.port = maxport + 1;
        }
        def->serials[def->nserials++] = chr;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./devices/console", ctxt, &nodes)) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot extract console devices"));
        goto error;
    }
    if (n && VIR_ALLOC_N(def->consoles, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt,
                                                         ctxt,
                                                         nodes[i],
                                                         flags);
        if (!chr)
            goto error;

        chr->target.port = i;
        def->consoles[def->nconsoles++] = chr;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./devices/channel", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->channels, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainChrDefPtr chr = virDomainChrDefParseXML(xmlopt,
                                                         ctxt,
                                                         nodes[i],
                                                         flags);
        if (!chr)
            goto error;

        def->channels[def->nchannels++] = chr;
    }
    VIR_FREE(nodes);


    /* analysis of the input devices */
    if ((n = virXPathNodeSet("./devices/input", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->inputs, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainInputDefPtr input = virDomainInputDefParseXML(xmlopt,
                                                               def,
                                                               nodes[i],
                                                               ctxt,
                                                               flags);
        if (!input)
            goto error;

        /* Check if USB bus is required */
        if (input->bus == VIR_DOMAIN_INPUT_BUS_USB && usb_none) {
            virDomainInputDefFree(input);
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB input device. "
                             "USB bus is disabled"));
            goto error;
        }

        def->inputs[def->ninputs++] = input;
    }
    VIR_FREE(nodes);

    /* analysis of the graphics devices */
    if ((n = virXPathNodeSet("./devices/graphics", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->graphics, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainGraphicsDefPtr graphics = virDomainGraphicsDefParseXML(xmlopt,
                                                                        nodes[i],
                                                                        ctxt,
                                                                        flags);
        if (!graphics)
            goto error;

        def->graphics[def->ngraphics++] = graphics;
    }
    VIR_FREE(nodes);

    /* analysis of the sound devices */
    if ((n = virXPathNodeSet("./devices/sound", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->sounds, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainSoundDefPtr sound = virDomainSoundDefParseXML(xmlopt,
                                                               nodes[i],
                                                               ctxt,
                                                               flags);
        if (!sound)
            goto error;

        def->sounds[def->nsounds++] = sound;
    }
    VIR_FREE(nodes);

    /* analysis of the video devices */
    if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->videos, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainVideoDefPtr video;
        ssize_t insertAt = -1;

        if (!(video = virDomainVideoDefParseXML(xmlopt, nodes[i],
                                                ctxt, flags)))
            goto error;

        if (video->primary) {
            if (def->nvideos != 0 && def->videos[0]->primary) {
                virDomainVideoDefFree(video);
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Only one primary video device is supported"));
                goto error;
            }

            insertAt = 0;
        }
        if (VIR_INSERT_ELEMENT_INPLACE(def->videos,
                                       insertAt,
                                       def->nvideos,
                                       video) < 0) {
            virDomainVideoDefFree(video);
            goto error;
        }
    }

    VIR_FREE(nodes);

    /* analysis of the host devices */
    if ((n = virXPathNodeSet("./devices/hostdev", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_REALLOC_N(def->hostdevs, def->nhostdevs + n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainHostdevDefPtr hostdev;

        hostdev = virDomainHostdevDefParseXML(xmlopt, nodes[i], ctxt,
                                              flags);
        if (!hostdev)
            goto error;

        if (hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB &&
            usb_none) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add host USB device: "
                             "USB is disabled in this host"));
            virDomainHostdevDefFree(hostdev);
            goto error;
        }

        def->hostdevs[def->nhostdevs++] = hostdev;

        /* For a domain definition, we need to check if the controller
         * for this hostdev exists yet and if not add it. This cannot be
         * done during virDomainHostdevAssignAddress (as part of device
         * post processing) because that will result in the failure to
         * load the controller during hostdev hotplug.
         */
        if (virDomainDefMaybeAddHostdevSCSIcontroller(def) < 0)
            goto error;
    }
    VIR_FREE(nodes);

    /* analysis of the watchdog devices */
    def->watchdog = NULL;
    if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0)
        goto error;
    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single watchdog device is supported"));
        goto error;
    }
    if (n > 0) {
        virDomainWatchdogDefPtr watchdog;

        watchdog = virDomainWatchdogDefParseXML(xmlopt, nodes[0], flags);
        if (!watchdog)
            goto error;

        def->watchdog = watchdog;
        VIR_FREE(nodes);
    }

    /* analysis of the memballoon devices */
    def->memballoon = NULL;
    if ((n = virXPathNodeSet("./devices/memballoon", ctxt, &nodes)) < 0)
        goto error;
    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single memory balloon device is supported"));
        goto error;
    }
    if (n > 0) {
        virDomainMemballoonDefPtr memballoon;

        memballoon = virDomainMemballoonDefParseXML(xmlopt, nodes[0], ctxt, flags);
        if (!memballoon)
            goto error;

        def->memballoon = memballoon;
        VIR_FREE(nodes);
    }

    /* Parse the RNG devices */
    if ((n = virXPathNodeSet("./devices/rng", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->rngs, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainRNGDefPtr rng = virDomainRNGDefParseXML(xmlopt, nodes[i],
                                                         ctxt, flags);
        if (!rng)
            goto error;

        def->rngs[def->nrngs++] = rng;
    }
    VIR_FREE(nodes);

    /* Parse the TPM devices */
    if ((n = virXPathNodeSet("./devices/tpm", ctxt, &nodes)) < 0)
        goto error;

    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only a single TPM device is supported"));
        goto error;
    }

    if (n > 0) {
        if (!(def->tpm = virDomainTPMDefParseXML(xmlopt, nodes[0], ctxt, flags)))
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./devices/nvram", ctxt, &nodes)) < 0)
        goto error;

    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only a single nvram device is supported"));
        goto error;
    } else if (n == 1) {
        virDomainNVRAMDefPtr nvram =
            virDomainNVRAMDefParseXML(xmlopt, nodes[0], flags);
        if (!nvram)
            goto error;
        def->nvram = nvram;
        VIR_FREE(nodes);
    }

    /* analysis of the hub devices */
    if ((n = virXPathNodeSet("./devices/hub", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->hubs, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainHubDefPtr hub;

        hub = virDomainHubDefParseXML(xmlopt, nodes[i], flags);
        if (!hub)
            goto error;

        if (hub->type == VIR_DOMAIN_HUB_TYPE_USB && usb_none) {
            virDomainHubDefFree(hub);
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("Can't add USB hub: "
                             "USB is disabled for this domain"));
            goto error;
        }

        def->hubs[def->nhubs++] = hub;
    }
    VIR_FREE(nodes);

    /* analysis of the redirected devices */
    if ((n = virXPathNodeSet("./devices/redirdev", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->redirdevs, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainRedirdevDefPtr redirdev =
            virDomainRedirdevDefParseXML(xmlopt, nodes[i], ctxt, flags);
        if (!redirdev)
            goto error;

        def->redirdevs[def->nredirdevs++] = redirdev;
    }
    VIR_FREE(nodes);

    /* analysis of the redirection filter rules */
    if ((n = virXPathNodeSet("./devices/redirfilter", ctxt, &nodes)) < 0)
        goto error;
    if (n > 1) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("only one set of redirection filter rule is supported"));
        goto error;
    }

    if (n) {
        virDomainRedirFilterDefPtr redirfilter =
            virDomainRedirFilterDefParseXML(nodes[0], ctxt);
        if (!redirfilter)
            goto error;

        def->redirfilter = redirfilter;
    }
    VIR_FREE(nodes);

    /* analysis of the panic devices */
    if ((n = virXPathNodeSet("./devices/panic", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->panics, n) < 0)
        goto error;
    for (i = 0; i < n; i++) {
        virDomainPanicDefPtr panic;

        panic = virDomainPanicDefParseXML(xmlopt, nodes[i], flags);
        if (!panic)
            goto error;

        def->panics[def->npanics++] = panic;
    }
    VIR_FREE(nodes);

    /* analysis of the shmem devices */
    if ((n = virXPathNodeSet("./devices/shmem", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->shmems, n) < 0)
        goto error;

    node = ctxt->node;
    for (i = 0; i < n; i++) {
        virDomainShmemDefPtr shmem;
        ctxt->node = nodes[i];
        shmem = virDomainShmemDefParseXML(xmlopt, nodes[i], ctxt, flags);
        if (!shmem)
            goto error;

        def->shmems[def->nshmems++] = shmem;
    }
    ctxt->node = node;
    VIR_FREE(nodes);

    /* Check for SEV feature */
    if ((node = virXPathNode("./launchSecurity", ctxt)) != NULL) {
        def->sev = virDomainSEVDefParseXML(node, ctxt);
        if (!def->sev)
            goto error;
    }

    /* analysis of memory devices */
    if ((n = virXPathNodeSet("./devices/memory", ctxt, &nodes)) < 0)
        goto error;
    if (n && VIR_ALLOC_N(def->mems, n) < 0)
        goto error;

    for (i = 0; i < n; i++) {
        virDomainMemoryDefPtr mem = virDomainMemoryDefParseXML(xmlopt,
                                                               nodes[i],
                                                               ctxt,
                                                               def,
                                                               flags);
        if (!mem)
            goto error;

        def->mems[def->nmems++] = mem;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./devices/iommu", ctxt, &nodes)) < 0)
        goto error;

    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only a single IOMMU device is supported"));
        goto error;
    }

    if (n > 0) {
        if (!(def->iommu = virDomainIOMMUDefParseXML(nodes[0], ctxt)))
            goto error;
    }
    VIR_FREE(nodes);

    if ((n = virXPathNodeSet("./devices/vsock", ctxt, &nodes)) < 0)
        goto error;

    if (n > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only a single vsock device is supported"));
        goto error;
    }

    if (n > 0) {
        if (!(def->vsock = virDomainVsockDefParseXML(xmlopt, nodes[0],
                                                     ctxt, flags)))
            goto error;
    }
    VIR_FREE(nodes);

    /* analysis of the user namespace mapping */
    if ((n = virXPathNodeSet("./idmap/uid", ctxt, &nodes)) < 0)
        goto error;

    if (n) {
        def->idmap.uidmap = virDomainIdmapDefParseXML(ctxt, nodes, n);
        if (!def->idmap.uidmap)
            goto error;

        def->idmap.nuidmap = n;
    }
    VIR_FREE(nodes);

    if  ((n = virXPathNodeSet("./idmap/gid", ctxt, &nodes)) < 0)
        goto error;

    if (n) {
        def->idmap.gidmap =  virDomainIdmapDefParseXML(ctxt, nodes, n);
        if (!def->idmap.gidmap)
            goto error;

        def->idmap.ngidmap = n;
    }

    if ((def->idmap.uidmap && !def->idmap.gidmap) ||
        (!def->idmap.uidmap && def->idmap.gidmap)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("uid and gid should be mapped both"));
            goto error;
    }

    if ((node = virXPathNode("./sysinfo[1]", ctxt)) != NULL) {
        xmlNodePtr oldnode = ctxt->node;
        ctxt->node = node;
        def->sysinfo = virSysinfoParseXML(node, ctxt,
                                          def->uuid, uuid_generated);
        ctxt->node = oldnode;

        if (def->sysinfo == NULL)
            goto error;
    }

    if ((tmp = virXPathString("string(./os/smbios/@mode)", ctxt))) {
        int mode;

        if ((mode = virDomainSmbiosModeTypeFromString(tmp)) < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown smbios mode '%s'"), tmp);
            goto error;
        }
        def->os.smbios_mode = mode;
    }

    if (virDomainKeyWrapDefParseXML(def, ctxt) < 0)
        goto error;

    /* Extract custom metadata */
    if ((node = virXPathNode("./metadata[1]", ctxt)) != NULL)
        def->metadata = xmlCopyNode(node, 1);

    /* we have to make a copy of all of the callback pointers here since
     * we won't have the virCaps structure available during free
     */
    def->ns = xmlopt->ns;

    if (def->ns.parse) {
        if (virXMLNamespaceRegister(ctxt, &def->ns) < 0)
            goto error;
        if ((def->ns.parse)(ctxt, &def->namespaceData) < 0)
            goto error;
    }

    return def;

 error:
    virDomainDefFree(def);
    return NULL;
}