virSecurityLabelDefParseXML(xmlXPathContextPtr ctxt,
                            unsigned int flags)
{
    char *p;
    virSecurityLabelDefPtr seclabel = NULL;

    p = virXMLPropStringLimit(ctxt->node, "model",
                              VIR_SECURITY_MODEL_BUFLEN - 1);

    if (!(seclabel = virSecurityLabelDefNew(p)))
        goto error;
    VIR_FREE(p);

    /* set default value */
    seclabel->type = VIR_DOMAIN_SECLABEL_DYNAMIC;

    p = virXMLPropStringLimit(ctxt->node, "type",
                              VIR_SECURITY_LABEL_BUFLEN - 1);
    if (p) {
        seclabel->type = virDomainSeclabelTypeFromString(p);
        if (seclabel->type <= 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("invalid security type '%s'"), p);
            goto error;
        }
    }

    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
        seclabel->type == VIR_DOMAIN_SECLABEL_NONE)
        seclabel->relabel = false;

    VIR_FREE(p);
    p = virXMLPropStringLimit(ctxt->node, "relabel",
                              VIR_SECURITY_LABEL_BUFLEN-1);
    if (p) {
        if (virStringParseYesNo(p, &seclabel->relabel) < 0) {
            virReportError(VIR_ERR_XML_ERROR,
                           _("invalid security relabel value %s"), p);
            goto error;
        }
    }
    VIR_FREE(p);

    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC &&
        !seclabel->relabel) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("dynamic label type must use resource relabeling"));
        goto error;
    }
    if (seclabel->type == VIR_DOMAIN_SECLABEL_NONE &&
        seclabel->relabel) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("resource relabeling is not compatible with 'none' label type"));
        goto error;
    }

    /* For the model 'none' none of the following labels is going to be
     * present. Hence, return now. */

    if (STREQ_NULLABLE(seclabel->model, "none")) {
        if (flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) {
            /* Fix older configurations */
            seclabel->type = VIR_DOMAIN_SECLABEL_NONE;
            seclabel->relabel = false;
        } else {
            if (seclabel->type != VIR_DOMAIN_SECLABEL_NONE) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unsupported type='%s' to model 'none'"),
                               virDomainSeclabelTypeToString(seclabel->type));
                goto error;
            }
            /* combination of relabel='yes' and type='static'
             * is checked a few lines above. */
        }
        return seclabel;
    }

    /* Only parse label, if using static labels, or
     * if the 'live' VM XML is requested
     */
    if (seclabel->type == VIR_DOMAIN_SECLABEL_STATIC ||
        (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
        p = virXPathStringLimit("string(./label[1])",
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
        if (p == NULL) {
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security label is missing"));
            goto error;
        }

        seclabel->label = g_steal_pointer(&p);
    }

    /* Only parse imagelabel, if requested live XML with relabeling */
    if (seclabel->relabel &&
        (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) &&
         seclabel->type != VIR_DOMAIN_SECLABEL_NONE)) {
        p = virXPathStringLimit("string(./imagelabel[1])",
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
        if (p == NULL) {
            virReportError(VIR_ERR_XML_ERROR,
                           "%s", _("security imagelabel is missing"));
            goto error;
        }
        seclabel->imagelabel = g_steal_pointer(&p);
    }

    /* Only parse baselabel for dynamic label type */
    if (seclabel->type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
        p = virXPathStringLimit("string(./baselabel[1])",
                                VIR_SECURITY_LABEL_BUFLEN-1, ctxt);
        seclabel->baselabel = g_steal_pointer(&p);
    }

    return seclabel;

 error:
    VIR_FREE(p);
    virSecurityLabelDefFree(seclabel);
    return NULL;
}