virDomainChrSourceDefFormat(virBufferPtr buf,
                            virDomainChrSourceDefPtr def,
                            unsigned int flags)
{
    g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
    g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);

    switch ((virDomainChrType)def->type) {
    case VIR_DOMAIN_CHR_TYPE_NULL:
    case VIR_DOMAIN_CHR_TYPE_VC:
    case VIR_DOMAIN_CHR_TYPE_STDIO:
    case VIR_DOMAIN_CHR_TYPE_SPICEVMC:
    case VIR_DOMAIN_CHR_TYPE_LAST:
        /* nada */
        break;

    case VIR_DOMAIN_CHR_TYPE_PTY:
    case VIR_DOMAIN_CHR_TYPE_DEV:
    case VIR_DOMAIN_CHR_TYPE_FILE:
    case VIR_DOMAIN_CHR_TYPE_PIPE:
        if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
            (def->data.file.path &&
             !(flags & VIR_DOMAIN_DEF_FORMAT_INACTIVE))) {
            virBufferEscapeString(&attrBuf, " path='%s'",
                                  def->data.file.path);
            if (def->type == VIR_DOMAIN_CHR_TYPE_FILE &&
                def->data.file.append != VIR_TRISTATE_SWITCH_ABSENT)
                virBufferAsprintf(&attrBuf, " append='%s'",
                    virTristateSwitchTypeToString(def->data.file.append));
            virDomainSourceDefFormatSeclabel(&childBuf, def->nseclabels,
                                             def->seclabels, flags);

            virXMLFormatElement(buf, "source", &attrBuf, &childBuf);
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_NMDM:
        virBufferEscapeString(buf, "<source master='%s' ",
                              def->data.nmdm.master);
        virBufferEscapeString(buf, "slave='%s'/>\n", def->data.nmdm.slave);
        break;

    case VIR_DOMAIN_CHR_TYPE_UDP:
        if (def->data.udp.bindService || def->data.udp.bindHost) {
            virBufferAddLit(buf, "<source mode='bind'");
            virBufferEscapeString(buf, " host='%s'", def->data.udp.bindHost);
            virBufferEscapeString(buf, " service='%s'", def->data.udp.bindService);
            virBufferAddLit(buf, "/>\n");
        }

        if (def->data.udp.connectService || def->data.udp.connectHost) {
            virBufferAddLit(buf, "<source mode='connect'");
            virBufferEscapeString(buf, " host='%s'", def->data.udp.connectHost);
            virBufferEscapeString(buf, " service='%s'", def->data.udp.connectService);
            virBufferAddLit(buf, "/>\n");
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_TCP:
        virBufferAsprintf(&attrBuf, " mode='%s' ",
                          def->data.tcp.listen ? "bind" : "connect");
        virBufferEscapeString(&attrBuf, "host='%s' ", def->data.tcp.host);
        virBufferEscapeString(&attrBuf, "service='%s'", def->data.tcp.service);
        if (def->data.tcp.haveTLS != VIR_TRISTATE_BOOL_ABSENT &&
            !(flags & VIR_DOMAIN_DEF_FORMAT_MIGRATABLE &&
              def->data.tcp.tlsFromConfig))
            virBufferAsprintf(&attrBuf, " tls='%s'",
                    virTristateBoolTypeToString(def->data.tcp.haveTLS));
        if (flags & VIR_DOMAIN_DEF_FORMAT_STATUS)
            virBufferAsprintf(&attrBuf, " tlsFromConfig='%d'",
                              def->data.tcp.tlsFromConfig);

        virDomainChrSourceReconnectDefFormat(&childBuf,
                                             &def->data.tcp.reconnect);

        virXMLFormatElement(buf, "source", &attrBuf, &childBuf);

        virBufferAsprintf(buf, "<protocol type='%s'/>\n",
                          virDomainChrTcpProtocolTypeToString(
                              def->data.tcp.protocol));
        break;

    case VIR_DOMAIN_CHR_TYPE_UNIX:
        if (def->data.nix.path) {
            virBufferAsprintf(&attrBuf, " mode='%s'",
                              def->data.nix.listen ? "bind" : "connect");
            virBufferEscapeString(&attrBuf, " path='%s'", def->data.nix.path);
            virDomainSourceDefFormatSeclabel(&childBuf, def->nseclabels,
                                             def->seclabels, flags);

            virDomainChrSourceReconnectDefFormat(&childBuf,
                                                 &def->data.nix.reconnect);

            virXMLFormatElement(buf, "source", &attrBuf, &childBuf);
        }
        break;

    case VIR_DOMAIN_CHR_TYPE_SPICEPORT:
        virBufferEscapeString(buf, "<source channel='%s'/>\n",
                              def->data.spiceport.channel);
        break;

    }

    if (def->logfile) {
        virBufferEscapeString(buf, "<log file='%s'", def->logfile);
        if (def->logappend != VIR_TRISTATE_SWITCH_ABSENT) {
            virBufferAsprintf(buf, " append='%s'",
                              virTristateSwitchTypeToString(def->logappend));
        }
        virBufferAddLit(buf, "/>\n");
    }

    return 0;
}