virSecurityLabelDefsParseXML(virDomainDefPtr def,
                             xmlXPathContextPtr ctxt,
                             virDomainXMLOptionPtr xmlopt,
                             unsigned int flags)
{
    VIR_XPATH_NODE_AUTORESTORE(ctxt);
    size_t i = 0, j;
    int n;
    g_autofree xmlNodePtr *list = NULL;

    /* Allocate a security labels based on XML */
    if ((n = virXPathNodeSet("./seclabel", ctxt, &list)) < 0)
        goto error;
    if (n == 0)
        return 0;

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

    /* Parse each "seclabel" tag */
    for (i = 0; i < n; i++) {
        virSecurityLabelDefPtr seclabel;

        ctxt->node = list[i];
        if (!(seclabel = virSecurityLabelDefParseXML(ctxt, flags)))
            goto error;

        for (j = 0; j < i; j++) {
            if (STREQ_NULLABLE(seclabel->model, def->seclabels[j]->model)) {
                virReportError(VIR_ERR_XML_DETAIL,
                               _("seclabel for model %s is already provided"),
                               seclabel->model);
                virSecurityLabelDefFree(seclabel);
                goto error;
            }
        }

        def->seclabels[i] = seclabel;
    }
    def->nseclabels = n;

    /* libvirt versions prior to 0.10.0 support just a single seclabel element
     * in guest's XML and model attribute can be suppressed if type is none or
     * type is dynamic, baselabel is not defined and INACTIVE flag is set.
     *
     * To avoid compatibility issues, for this specific case the first model
     * defined in host's capabilities is used as model for the seclabel.
     */
    if (def->nseclabels == 1 &&
        !def->seclabels[0]->model &&
        xmlopt != NULL &&
        xmlopt->config.defSecModel != NULL) {
        if (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_NONE ||
            (def->seclabels[0]->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
             !def->seclabels[0]->baselabel &&
             (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE))) {
            /* Copy model from host. */
            VIR_DEBUG("Found seclabel without a model, using '%s'",
                      xmlopt->config.defSecModel);
            def->seclabels[0]->model = g_strdup(xmlopt->config.defSecModel);

            if (STREQ(def->seclabels[0]->model, "none") &&
                flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
                /* Fix older configurations */
                def->seclabels[0]->type = VIR_DOMAIN_SECLABEL_NONE;
                def->seclabels[0]->relabel = false;
            }
        } else {
            virReportError(VIR_ERR_XML_ERROR, "%s",
                           _("missing security model in domain seclabel"));
            goto error;
        }
    }

    /* Checking missing model information */
    if (def->nseclabels > 1) {
        for (; n; n--) {
            if (def->seclabels[n - 1]->model == NULL) {
                virReportError(VIR_ERR_XML_ERROR, "%s",
                               _("missing security model "
                                 "when using multiple labels"));
                goto error;
            }
        }
    }

    return 0;

 error:
    for (; i > 0; i--)
        virSecurityLabelDefFree(def->seclabels[i - 1]);
    VIR_FREE(def->seclabels);
    def->nseclabels = 0;
    return -1;
}