/*
   Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com>
   This file is part of GlusterFS.

   This file is licensed to you under your choice of the GNU Lesser
   General Public License, version 3 or any later version (LGPLv3 or
   later), or the GNU General Public License, version 2 (GPLv2), in all
   cases as published by the Free Software Foundation.
*/
#include <stdlib.h>
#include "cli.h"
#include "cli1-xdr.h"
#include <glusterfs/run.h>
#include <glusterfs/compat.h>
#include <glusterfs/syscall.h>
#include <glusterfs/upcall-utils.h>

enum gf_task_types { GF_TASK_TYPE_REBALANCE, GF_TASK_TYPE_REMOVE_BRICK };

/*
 * IMPORTANT NOTE:
 * All exported functions in this file which use libxml need use a
 * #if (HAVE_LIB_XML), #else, #endif
 * For eg,
 *      int exported_func () {
 *              #if (HAVE_LIB_XML)
 *                      <Stuff using libxml>
 *              #else
 *                      return 0;
 *              #endif
 *      }
 *
 *  All other functions, which are called internally within this file need to be
 *  within #if (HAVE_LIB_XML), #endif statements
 *  For eg,
 *      #if (HAVE_LIB_XML)
 *      int internal_func ()
 *      {
 *      }
 *      #endif
 *
 *  Following the above format ensures that all xml related code is compiled
 *  only when libxml2 is present, and also keeps the rest of the codebase free
 *  of #if (HAVE_LIB_XML)
 */

#if (HAVE_LIB_XML)

#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>

#define XML_RET_CHECK_AND_GOTO(ret, label)                                     \
    do {                                                                       \
        if (ret < 0) {                                                         \
            ret = -1;                                                          \
            goto label;                                                        \
        } else                                                                 \
            ret = 0;                                                           \
    } while (0)

int
cli_begin_xml_output(xmlTextWriterPtr *writer, xmlDocPtr *doc)
{
    int ret = -1;

    *writer = xmlNewTextWriterDoc(doc, 0);
    if (*writer == NULL) {
        ret = -1;
        goto out;
    }

    ret = xmlTextWriterStartDocument(*writer, "1.0", "UTF-8", "yes");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <cliOutput> */
    ret = xmlTextWriterStartElement(*writer, (xmlChar *)"cliOutput");
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_end_xml_output(xmlTextWriterPtr writer, xmlDocPtr doc)
{
    int ret = -1;

    /* </cliOutput> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterEndDocument(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* Dump xml document to stdout and pretty format it */
    xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);

    xmlFreeTextWriter(writer);
    xmlFreeDoc(doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_common(xmlTextWriterPtr writer, int op_ret, int op_errno,
                      char *op_errstr)
{
    int ret = -1;

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opRet", "%d",
                                          op_ret);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opErrno", "%d",
                                          op_errno);
    XML_RET_CHECK_AND_GOTO(ret, out);

    if (op_errstr)
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opErrstr",
                                              "%s", op_errstr);
    else
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opErrstr",
                                              "%s", "");

    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_str(char *op, char *str, int op_ret, int op_errno,
                   char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    if (op) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"cliOp", "%s",
                                              op);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    if (str) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"output", "%s",
                                              str);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
int
cli_xml_output_data_pair(dict_t *this, char *key, data_t *value, void *data)
{
    int ret = -1;
    xmlTextWriterPtr *writer = NULL;

    writer = (xmlTextWriterPtr *)data;

    ret = xmlTextWriterWriteFormatElement(*writer, (xmlChar *)key, "%s",
                                          value->data);

    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    return ret;
}
#endif

int
cli_xml_output_dict(char *op, dict_t *dict, int op_ret, int op_errno,
                    char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <"op"> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)op);
    XML_RET_CHECK_AND_GOTO(ret, out);

    if (dict)
        dict_foreach(dict, cli_xml_output_data_pair, &writer);

    /* </"op"> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(writer, doc);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
int
cli_xml_output_vol_status_common(xmlTextWriterPtr writer, dict_t *dict,
                                 int brick_index, int *online,
                                 gf_boolean_t *node_present)
{
    int ret = -1;
    char *hostname = NULL;
    char *path = NULL;
    char *uuid = NULL;
    int port = 0;
    int rdma_port = 0;
    int status = 0;
    int pid = 0;
    char key[1024] = {
        0,
    };

    snprintf(key, sizeof(key), "brick%d.hostname", brick_index);
    ret = dict_get_str(dict, key, &hostname);
    if (ret) {
        *node_present = _gf_false;
        goto out;
    }
    *node_present = _gf_true;

    /* <node>
     * will be closed in the calling function cli_xml_output_vol_status()*/
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"node");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hostname", "%s",
                                          hostname);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.path", brick_index);
    ret = dict_get_str(dict, key, &path);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"path", "%s",
                                          path);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.peerid", brick_index);
    ret = dict_get_str(dict, key, &uuid);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"peerid", "%s",
                                          uuid);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.status", brick_index);
    ret = dict_get_int32(dict, key, &status);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status", "%d",
                                          status);
    XML_RET_CHECK_AND_GOTO(ret, out);
    *online = status;

    snprintf(key, sizeof(key), "brick%d.port", brick_index);
    ret = dict_get_int32(dict, key, &port);
    if (ret)
        goto out;

    snprintf(key, sizeof(key), "brick%d.rdma_port", brick_index);
    ret = dict_get_int32(dict, key, &rdma_port);

    /* If the process is either offline or doesn't provide a port (shd)
     * port = "N/A"
     * else print the port number of the process.
     */

    /*
     * Tag 'port' can be removed once console management is started
     * to support new tag ports.
     */

    if (*online == 1 && port != 0)
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"port", "%d",
                                              port);
    else
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"port", "%s",
                                              "N/A");
    XML_RET_CHECK_AND_GOTO(ret, out);
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"ports");
    if (*online == 1 && (port != 0 || rdma_port != 0)) {
        if (port) {
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"tcp",
                                                  "%d", port);
        } else {
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"tcp",
                                                  "%s", "N/A");
        }
        XML_RET_CHECK_AND_GOTO(ret, out);
        if (rdma_port) {
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"rdma",
                                                  "%d", rdma_port);
        } else {
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"rdma",
                                                  "%s", "N/A");
        }
        XML_RET_CHECK_AND_GOTO(ret, out);
    } else {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"tcp", "%s",
                                              "N/A");
        XML_RET_CHECK_AND_GOTO(ret, out);
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"rdma", "%s",
                                              "N/A");
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.pid", brick_index);
    ret = dict_get_int32(dict, key, &pid);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"pid", "%d", pid);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_detail(xmlTextWriterPtr writer, dict_t *dict,
                                 int brick_index)
{
    int ret = -1;
    uint64_t size_total = 0;
    uint64_t size_free = 0;
    char *device = NULL;
    uint64_t block_size = 0;
    char *mnt_options = NULL;
    char *fs_name = NULL;
    char *inode_size = NULL;
    uint64_t inodes_total = 0;
    uint64_t inodes_free = 0;
    char key[1024] = {
        0,
    };

    snprintf(key, sizeof(key), "brick%d.total", brick_index);
    ret = dict_get_uint64(dict, key, &size_total);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"sizeTotal",
                                              "%" PRIu64, size_total);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.free", brick_index);
    ret = dict_get_uint64(dict, key, &size_free);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"sizeFree",
                                              "%" PRIu64, size_free);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.device", brick_index);
    ret = dict_get_str(dict, key, &device);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"device", "%s",
                                              device);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.block_size", brick_index);
    ret = dict_get_uint64(dict, key, &block_size);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"blockSize",
                                              "%" PRIu64, block_size);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.mnt_options", brick_index);
    ret = dict_get_str(dict, key, &mnt_options);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"mntOptions",
                                              "%s", mnt_options);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.fs_name", brick_index);
    ret = dict_get_str(dict, key, &fs_name);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"fsName", "%s",
                                              fs_name);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.inode_size", brick_index);
    ret = dict_get_str(dict, key, &inode_size);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"inodeSize",
                                              "%s", fs_name);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.total_inodes", brick_index);
    ret = dict_get_uint64(dict, key, &inodes_total);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"inodesTotal",
                                              "%" PRIu64, inodes_total);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    snprintf(key, sizeof(key), "brick%d.free_inodes", brick_index);
    ret = dict_get_uint64(dict, key, &inodes_free);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"inodesFree",
                                              "%" PRIu64, inodes_free);
        XML_RET_CHECK_AND_GOTO(ret, out);
    } else {
        ret = 0;
    }

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_mempool(xmlTextWriterPtr writer, dict_t *dict,
                                  char *prefix)
{
    int ret = -1;
    int mempool_count = 0;
    char *name = NULL;
    int hotcount = 0;
    int coldcount = 0;
    uint64_t paddedsizeof = 0;
    uint64_t alloccount = 0;
    int maxalloc = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <mempool> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"mempool");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.mempool-count", prefix);
    ret = dict_get_int32(dict, key, &mempool_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
                                          mempool_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < mempool_count; i++) {
        /* <pool> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"pool");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.name", prefix, i);
        ret = dict_get_str(dict, key, &name);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              name);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.hotcount", prefix, i);
        ret = dict_get_int32(dict, key, &hotcount);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hotCount",
                                              "%d", hotcount);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.coldcount", prefix, i);
        ret = dict_get_int32(dict, key, &coldcount);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"coldCount",
                                              "%d", coldcount);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.paddedsizeof", prefix, i);
        ret = dict_get_uint64(dict, key, &paddedsizeof);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            writer, (xmlChar *)"padddedSizeOf", "%" PRIu64, paddedsizeof);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.alloccount", prefix, i);
        ret = dict_get_uint64(dict, key, &alloccount);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"allocCount",
                                              "%" PRIu64, alloccount);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.max_alloc", prefix, i);
        ret = dict_get_int32(dict, key, &maxalloc);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"maxAlloc",
                                              "%d", maxalloc);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.pool-misses", prefix, i);
        ret = dict_get_uint64(dict, key, &alloccount);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"poolMisses",
                                              "%" PRIu64, alloccount);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.pool%d.max-stdalloc", prefix, i);
        ret = dict_get_int32(dict, key, &maxalloc);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"maxStdAlloc",
                                              "%d", maxalloc);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </pool> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </mempool> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_mem(xmlTextWriterPtr writer, dict_t *dict,
                              int brick_index)
{
    int ret = -1;
    uint64_t arena = 0;
    uint64_t ordblks = 0;
    uint64_t smblks = 0;
    uint64_t hblks = 0;
    uint64_t hblkhd = 0;
    uint64_t usmblks = 0;
    uint64_t fsmblks = 0;
    uint64_t uordblks = 0;
    uint64_t fordblks = 0;
    uint64_t keepcost = 0;
    char key[1024] = {
        0,
    };

    /* <memStatus> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"memStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <mallinfo> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"mallinfo");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.arena", brick_index);
    ret = dict_get_uint64(dict, key, &arena);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"arena",
                                          "%" PRIu64, arena);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.ordblks", brick_index);
    ret = dict_get_uint64(dict, key, &ordblks);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"ordblks",
                                          "%" PRIu64, ordblks);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.smblks", brick_index);
    ret = dict_get_uint64(dict, key, &smblks);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"smblks",
                                          "%" PRIu64, smblks);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.hblks", brick_index);
    ret = dict_get_uint64(dict, key, &hblks);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hblks",
                                          "%" PRIu64, hblks);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.hblkhd", brick_index);
    ret = dict_get_uint64(dict, key, &hblkhd);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hblkhd",
                                          "%" PRIu64, hblkhd);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.usmblks", brick_index);
    ret = dict_get_uint64(dict, key, &usmblks);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"usmblks",
                                          "%" PRIu64, usmblks);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.fsmblks", brick_index);
    ret = dict_get_uint64(dict, key, &fsmblks);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"fsmblks",
                                          "%" PRIu64, fsmblks);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.uordblks", brick_index);
    ret = dict_get_uint64(dict, key, &uordblks);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uordblks",
                                          "%" PRIu64, uordblks);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.fordblks", brick_index);
    ret = dict_get_uint64(dict, key, &fordblks);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"fordblks",
                                          "%" PRIu64, fordblks);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.mallinfo.keepcost", brick_index);
    ret = dict_get_uint64(dict, key, &keepcost);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"keepcost",
                                          "%" PRIu64, keepcost);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </mallinfo> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d", brick_index);
    ret = cli_xml_output_vol_status_mempool(writer, dict, key);
    if (ret)
        goto out;

    /* </memStatus> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_clients(xmlTextWriterPtr writer, dict_t *dict,
                                  int brick_index)
{
    int ret = -1;
    int client_count = 0;
    char *hostname = NULL;
    uint64_t bytes_read = 0;
    uint64_t bytes_write = 0;
    uint32_t opversion = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <clientsStatus> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"clientsStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.clientcount", brick_index);
    ret = dict_get_int32(dict, key, &client_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"clientCount",
                                          "%d", client_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < client_count; i++) {
        /* <client> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"client");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "brick%d.client%d.hostname", brick_index, i);
        ret = dict_get_str(dict, key, &hostname);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hostname",
                                              "%s", hostname);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "brick%d.client%d.bytesread", brick_index,
                 i);
        ret = dict_get_uint64(dict, key, &bytes_read);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"bytesRead",
                                              "%" PRIu64, bytes_read);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "brick%d.client%d.byteswrite", brick_index,
                 i);
        ret = dict_get_uint64(dict, key, &bytes_write);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"bytesWrite",
                                              "%" PRIu64, bytes_write);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "brick%d.client%d.opversion", brick_index,
                 i);
        ret = dict_get_uint32(dict, key, &opversion);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opVersion",
                                              "%" PRIu32, opversion);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </client> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </clientsStatus> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_inode_entry(xmlTextWriterPtr writer, dict_t *dict,
                                      char *prefix)
{
    int ret = -1;
    char *gfid = NULL;
    uint64_t nlookup = 0;
    uint32_t ref = 0;
    int ia_type = 0;
    char key[1024] = {
        0,
    };

    /* <inode> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"inode");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.gfid", prefix);
    ret = dict_get_str(dict, key, &gfid);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"gfid", "%s",
                                          gfid);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.nlookup", prefix);
    ret = dict_get_uint64(dict, key, &nlookup);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"nLookup",
                                          "%" PRIu64, nlookup);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.ref", prefix);
    ret = dict_get_uint32(dict, key, &ref);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"ref", "%" PRIu32,
                                          ref);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.ia_type", prefix);
    ret = dict_get_int32(dict, key, &ia_type);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"iaType", "%d",
                                          ia_type);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </inode> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_itable(xmlTextWriterPtr writer, dict_t *dict,
                                 char *prefix)
{
    int ret = -1;
    uint32_t active_size = 0;
    uint32_t lru_size = 0;
    uint32_t purge_size = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    snprintf(key, sizeof(key), "%s.active_size", prefix);
    ret = dict_get_uint32(dict, key, &active_size);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"activeSize",
                                          "%" PRIu32, active_size);
    XML_RET_CHECK_AND_GOTO(ret, out);
    if (active_size != 0) {
        /* <active> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"active");
        XML_RET_CHECK_AND_GOTO(ret, out);

        for (i = 0; i < active_size; i++) {
            snprintf(key, sizeof(key), "%s.active%d", prefix, i);
            ret = cli_xml_output_vol_status_inode_entry(writer, dict, key);
            if (ret)
                goto out;
        }
        /* </active> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    snprintf(key, sizeof(key), "%s.lru_size", prefix);
    ret = dict_get_uint32(dict, key, &lru_size);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"lruSize",
                                          "%" PRIu32, lru_size);
    XML_RET_CHECK_AND_GOTO(ret, out);
    if (lru_size != 0) {
        /* <lru> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"lru");
        XML_RET_CHECK_AND_GOTO(ret, out);

        for (i = 0; i < lru_size; i++) {
            snprintf(key, sizeof(key), "%s.lru%d", prefix, i);
            ret = cli_xml_output_vol_status_inode_entry(writer, dict, key);
            if (ret)
                goto out;
        }
        /* </lru> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    snprintf(key, sizeof(key), "%s.purge_size", prefix);
    ret = dict_get_uint32(dict, key, &purge_size);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"purgeSize",
                                          "%" PRIu32, purge_size);
    XML_RET_CHECK_AND_GOTO(ret, out);
    if (purge_size != 0) {
        /* <purge> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"purge");
        XML_RET_CHECK_AND_GOTO(ret, out);

        for (i = 0; i < purge_size; i++) {
            snprintf(key, sizeof(key), "%s.purge%d", prefix, i);
            ret = cli_xml_output_vol_status_inode_entry(writer, dict, key);
            if (ret)
                goto out;
        }
        /* </purge> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_inode(xmlTextWriterPtr writer, dict_t *dict,
                                int brick_index)
{
    int ret = -1;
    int conn_count = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <inodeStatus> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"inodeStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.conncount", brick_index);
    ret = dict_get_int32(dict, key, &conn_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"connections",
                                          "%d", conn_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < conn_count; i++) {
        /* <connection> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"connection");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "brick%d.conn%d.itable", brick_index, i);
        ret = cli_xml_output_vol_status_itable(writer, dict, key);
        if (ret)
            goto out;

        /* </connection> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </inodeStatus> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_fdtable(xmlTextWriterPtr writer, dict_t *dict,
                                  char *prefix)
{
    int ret = -1;
    int refcount = 0;
    uint32_t maxfds = 0;
    int firstfree = 0;
    int openfds = 0;
    int fd_pid = 0;
    int fd_refcount = 0;
    int fd_flags = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <fdTable> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"fdTable");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.refcount", prefix);
    ret = dict_get_int32(dict, key, &refcount);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"refCount", "%d",
                                          refcount);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.maxfds", prefix);
    ret = dict_get_uint32(dict, key, &maxfds);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"maxFds",
                                          "%" PRIu32, maxfds);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.firstfree", prefix);
    ret = dict_get_int32(dict, key, &firstfree);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"firstFree", "%d",
                                          firstfree);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.openfds", prefix);
    ret = dict_get_int32(dict, key, &openfds);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"openFds", "%d",
                                          openfds);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < maxfds; i++) {
        snprintf(key, sizeof(key), "%s.fdentry%d.pid", prefix, i);
        ret = dict_get_int32(dict, key, &fd_pid);
        if (ret)
            continue;

        snprintf(key, sizeof(key), "%s.fdentry%d.refcount", prefix, i);
        ret = dict_get_int32(dict, key, &fd_refcount);
        if (ret)
            continue;

        snprintf(key, sizeof(key), "%s.fdentry%d.flags", prefix, i);
        ret = dict_get_int32(dict, key, &fd_flags);
        if (ret)
            continue;

        /* <fd> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"fd");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"entry", "%d",
                                              i + 1);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"pid", "%d",
                                              fd_pid);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"refCount",
                                              "%d", fd_refcount);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"flags", "%d",
                                              fd_flags);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </fd> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </fdTable> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_fd(xmlTextWriterPtr writer, dict_t *dict,
                             int brick_index)
{
    int ret = -1;
    int conn_count = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <fdStatus> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"fdStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.conncount", brick_index);
    ret = dict_get_int32(dict, key, &conn_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"connections",
                                          "%d", conn_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < conn_count; i++) {
        /* <connection> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"connection");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "brick%d.conn%d.fdtable", brick_index, i);
        ret = cli_xml_output_vol_status_fdtable(writer, dict, key);
        if (ret)
            goto out;

        /* </connection> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </fdStatus> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_callframe(xmlTextWriterPtr writer, dict_t *dict,
                                    char *prefix)
{
    int ret = -1;
    int ref_count = 0;
    char *translator = NULL;
    int complete = 0;
    char *parent = NULL;
    char *wind_from = NULL;
    char *wind_to = NULL;
    char *unwind_from = NULL;
    char *unwind_to = NULL;
    char key[1024] = {
        0,
    };

    /* <callFrame> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"callFrame");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.refcount", prefix);
    ret = dict_get_int32(dict, key, &ref_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"refCount", "%d",
                                          ref_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.translator", prefix);
    ret = dict_get_str(dict, key, &translator);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"translator", "%s",
                                          translator);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.complete", prefix);
    ret = dict_get_int32(dict, key, &complete);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"complete", "%d",
                                          complete);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.parent", prefix);
    ret = dict_get_str(dict, key, &parent);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"parent", "%s",
                                              parent);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    snprintf(key, sizeof(key), "%s.windfrom", prefix);
    ret = dict_get_str(dict, key, &wind_from);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"windFrom",
                                              "%s", wind_from);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    snprintf(key, sizeof(key), "%s.windto", prefix);
    ret = dict_get_str(dict, key, &wind_to);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"windTo", "%s",
                                              wind_to);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    snprintf(key, sizeof(key), "%s.unwindfrom", prefix);
    ret = dict_get_str(dict, key, &unwind_from);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"unwindFrom",
                                              "%s", unwind_from);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    snprintf(key, sizeof(key), "%s.unwindto", prefix);
    ret = dict_get_str(dict, key, &unwind_to);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"unwindTo",
                                              "%s", unwind_to);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </callFrame> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_callstack(xmlTextWriterPtr writer, dict_t *dict,
                                    char *prefix)
{
    int ret = -1;
    int uid = 0;
    int gid = 0;
    int pid = 0;
    uint64_t unique = 0;
    int frame_count = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <callStack> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"callStack");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.uid", prefix);
    ret = dict_get_int32(dict, key, &uid);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uid", "%d", uid);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.gid", prefix);
    ret = dict_get_int32(dict, key, &gid);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"gid", "%d", gid);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.pid", prefix);
    ret = dict_get_int32(dict, key, &pid);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"pid", "%d", pid);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.unique", prefix);
    ret = dict_get_uint64(dict, key, &unique);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"unique",
                                          "%" PRIu64, unique);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.count", prefix);
    ret = dict_get_int32(dict, key, &frame_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"frameCount", "%d",
                                          frame_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < frame_count; i++) {
        snprintf(key, sizeof(key), "%s.frame%d", prefix, i);
        ret = cli_xml_output_vol_status_callframe(writer, dict, key);
        if (ret)
            goto out;
    }

    /* </callStack> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_callpool(xmlTextWriterPtr writer, dict_t *dict,
                                   int brick_index)
{
    int ret = -1;
    int call_count = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <callpoolStatus> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"callpoolStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "brick%d.callpool.count", brick_index);
    ret = dict_get_int32(dict, key, &call_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
                                          call_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < call_count; i++) {
        snprintf(key, sizeof(key), "brick%d.callpool.stack%d", brick_index, i);
        ret = cli_xml_output_vol_status_callstack(writer, dict, key);
        if (ret)
            goto out;
    }

    /* </callpoolStatus> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_vol_status_begin(cli_local_t *local, int op_ret, int op_errno,
                                char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    ret = cli_begin_xml_output(&(local->writer), &(local->doc));
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_xml_output_common(local->writer, op_ret, op_errno, op_errstr);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <volStatus> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <volumes> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volumes");
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_status_end(cli_local_t *local)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    /* </volumes> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </volStatus> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(local->writer, local->doc);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
int
cli_xml_output_remove_brick_task_params(xmlTextWriterPtr writer, dict_t *dict,
                                        char *prefix)
{
    int ret = -1;
    char key[1024] = {
        0,
    };
    int count = 0;
    int i = 0;
    char *brick = NULL;

    /* <params> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"params");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.count", prefix);
    ret = dict_get_int32(dict, key, &count);
    if (ret)
        goto out;

    for (i = 1; i <= count; i++) {
        snprintf(key, sizeof(key), "%s.brick%d", prefix, i);
        ret = dict_get_str(dict, key, &brick);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"brick", "%s",
                                              brick);
        XML_RET_CHECK_AND_GOTO(ret, out);
        brick = NULL;
    }

    /* </param> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_status_tasks(cli_local_t *local, dict_t *dict)
{
    int ret = -1;
    char *task_type = NULL;
    char *task_id_str = NULL;
    int status = 0;
    int tasks = 0;
    char key[1024] = {
        0,
    };
    int i = 0;

    /* <tasks> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"tasks");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "tasks", &tasks);
    if (ret)
        goto out;

    for (i = 0; i < tasks; i++) {
        /* <task> */
        ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"task");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "task%d.type", i);
        ret = dict_get_str(dict, key, &task_type);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"type",
                                              "%s", task_type);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "task%d.id", i);
        ret = dict_get_str(dict, key, &task_id_str);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"id",
                                              "%s", task_id_str);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "task%d.status", i);
        ret = dict_get_int32(dict, key, &status);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"status", "%d", status);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(local->writer,
                                              (xmlChar *)"statusStr", "%s",
                                              cli_vol_task_status_str[status]);

        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "task%d", i);
        if (!strcmp(task_type, "Remove brick")) {
            ret = cli_xml_output_remove_brick_task_params(local->writer, dict,
                                                          key);
            if (ret)
                goto out;
        }

        /* </task> */
        ret = xmlTextWriterEndElement(local->writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </tasks> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

#endif

int
cli_xml_output_vol_status_tasks_detail(cli_local_t *local, dict_t *dict)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    char *volname = NULL;

    /*<volume>*/
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volume");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "volname", &volname);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"volName",
                                          "%s", volname);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_xml_output_vol_status_tasks(local, dict);
    if (ret)
        goto out;

    /* </volume> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_status(cli_local_t *local, dict_t *dict)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    char *volname = NULL;
    int brick_count = 0;
    int brick_index_max = -1;
    int other_count = 0;
    int index_max = 0;
    uint32_t cmd = GF_CLI_STATUS_NONE;
    int online = 0;
    gf_boolean_t node_present = _gf_true;
    int i;
    int type = -1;

    /* <volume> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volume");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "volname", &volname);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"volName",
                                          "%s", volname);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "count", &brick_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"nodeCount",
                                          "%d", brick_count);

    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_uint32(dict, "cmd", &cmd);
    if (ret)
        goto out;

    ret = dict_get_int32(dict, "brick-index-max", &brick_index_max);
    if (ret)
        goto out;
    ret = dict_get_int32(dict, "other-count", &other_count);
    if (ret)
        goto out;

    index_max = brick_index_max + other_count;

    ret = dict_get_int32(dict, "type", &type);
    if (ret)
        goto out;

    for (i = 0; i <= index_max; i++) {
        ret = cli_xml_output_vol_status_common(local->writer, dict, i, &online,
                                               &node_present);
        if (ret) {
            if (node_present)
                goto out;
            else
                continue;
        }

        switch (cmd & GF_CLI_STATUS_MASK) {
            case GF_CLI_STATUS_DETAIL:
                ret = cli_xml_output_vol_status_detail(local->writer, dict, i);
                if (ret)
                    goto out;
                break;

            case GF_CLI_STATUS_MEM:
                if (online) {
                    ret = cli_xml_output_vol_status_mem(local->writer, dict, i);
                    if (ret)
                        goto out;
                }
                break;

            case GF_CLI_STATUS_CLIENTS:
                if (online) {
                    ret = cli_xml_output_vol_status_clients(local->writer, dict,
                                                            i);
                    if (ret)
                        goto out;
                }
                break;

            case GF_CLI_STATUS_INODE:
                if (online) {
                    ret = cli_xml_output_vol_status_inode(local->writer, dict,
                                                          i);
                    if (ret)
                        goto out;
                }
                break;

            case GF_CLI_STATUS_FD:
                if (online) {
                    ret = cli_xml_output_vol_status_fd(local->writer, dict, i);
                    if (ret)
                        goto out;
                }
                break;

            case GF_CLI_STATUS_CALLPOOL:
                if (online) {
                    ret = cli_xml_output_vol_status_callpool(local->writer,
                                                             dict, i);
                    if (ret)
                        goto out;
                }
                break;
            default:
                break;
        }

        /* </node>  was opened in cli_xml_output_vol_status_common()*/
        ret = xmlTextWriterEndElement(local->writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* Tasks are only present when a normal volume status call is done on a
     * single volume or on all volumes
     */
    if (((cmd & GF_CLI_STATUS_MASK) == GF_CLI_STATUS_NONE) &&
        (cmd & (GF_CLI_STATUS_VOL | GF_CLI_STATUS_ALL))) {
        ret = cli_xml_output_vol_status_tasks(local, dict);
        if (ret)
            goto out;
    }

    /* </volume> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
int
cli_xml_output_vol_top_rw_perf(xmlTextWriterPtr writer, dict_t *dict,
                               int brick_index, int member_index)
{
    int ret = -1;
    char *filename = NULL;
    uint64_t throughput = 0;
    struct timeval tv = {
        0,
    };
    char timestr[GF_TIMESTR_SIZE] = {
        0,
    };
    char key[1024] = {
        0,
    };

    /* <file> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"file");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-filename-%d", brick_index, member_index);
    ret = dict_get_str(dict, key, &filename);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"filename", "%s",
                                          filename);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-value-%d", brick_index, member_index);
    ret = dict_get_uint64(dict, key, &throughput);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count",
                                          "%" PRIu64, throughput);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-time-sec-%d", brick_index, member_index);
    ret = dict_get_int32(dict, key, (int32_t *)&tv.tv_sec);
    if (ret)
        goto out;

    snprintf(key, sizeof(key), "%d-time-usec-%d", brick_index, member_index);
    ret = dict_get_int32(dict, key, (int32_t *)&tv.tv_usec);
    if (ret)
        goto out;

    gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT);
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"time", "%s",
                                          timestr);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </file> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

int
cli_xml_output_vol_top_other(xmlTextWriterPtr writer, dict_t *dict,
                             int brick_index, int member_index)
{
    int ret = -1;
    char *filename = NULL;
    uint64_t count = 0;
    char key[1024] = {
        0,
    };

    /* <file> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"file");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-filename-%d", brick_index, member_index);
    ret = dict_get_str(dict, key, &filename);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"filename", "%s",
                                          filename);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-value-%d", brick_index, member_index);
    ret = dict_get_uint64(dict, key, &count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count",
                                          "%" PRIu64, count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </file> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_vol_top(dict_t *dict, int op_ret, int op_errno, char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    int brick_count = 0;
    int top_op = GF_CLI_TOP_NONE;
    char *brick_name = NULL;
    int members = 0;
    uint64_t current_open = 0;
    uint64_t max_open = 0;
    char *max_open_time = NULL;
    double throughput = 0.0;
    double time_taken = 0.0;
    char key[1024] = {
        0,
    };
    int i = 0;
    int j = 0;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <volTop> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volTop");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "count", &brick_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"brickCount", "%d",
                                          brick_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "1-top-op", &top_op);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"topOp", "%d",
                                          top_op);
    XML_RET_CHECK_AND_GOTO(ret, out);

    while (i < brick_count) {
        i++;

        /* <brick> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"brick");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%d-brick", i);
        ret = dict_get_str(dict, key, &brick_name);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              brick_name);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%d-members", i);
        ret = dict_get_int32(dict, key, &members);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"members",
                                              "%d", members);
        XML_RET_CHECK_AND_GOTO(ret, out);

        switch (top_op) {
            case GF_CLI_TOP_OPEN:
                snprintf(key, sizeof(key), "%d-current-open", i);
                ret = dict_get_uint64(dict, key, &current_open);
                if (ret)
                    goto out;
                ret = xmlTextWriterWriteFormatElement(
                    writer, (xmlChar *)"currentOpen", "%" PRIu64, current_open);
                XML_RET_CHECK_AND_GOTO(ret, out);

                snprintf(key, sizeof(key), "%d-max-open", i);
                ret = dict_get_uint64(dict, key, &max_open);
                if (ret)
                    goto out;
                ret = xmlTextWriterWriteFormatElement(
                    writer, (xmlChar *)"maxOpen", "%" PRIu64, max_open);
                XML_RET_CHECK_AND_GOTO(ret, out);

                snprintf(key, sizeof(key), "%d-max-openfd-time", i);
                ret = dict_get_str(dict, key, &max_open_time);
                if (ret)
                    goto out;
                ret = xmlTextWriterWriteFormatElement(
                    writer, (xmlChar *)"maxOpenTime", "%s", max_open_time);
                XML_RET_CHECK_AND_GOTO(ret, out);

            case GF_CLI_TOP_READ:
            case GF_CLI_TOP_WRITE:
            case GF_CLI_TOP_OPENDIR:
            case GF_CLI_TOP_READDIR:

                break;

            case GF_CLI_TOP_READ_PERF:
            case GF_CLI_TOP_WRITE_PERF:
                snprintf(key, sizeof(key), "%d-throughput", i);
                ret = dict_get_double(dict, key, &throughput);
                if (!ret) {
                    snprintf(key, sizeof(key), "%d-time", i);
                    ret = dict_get_double(dict, key, &time_taken);
                }

                if (!ret) {
                    ret = xmlTextWriterWriteFormatElement(
                        writer, (xmlChar *)"throughput", "%f", throughput);
                    XML_RET_CHECK_AND_GOTO(ret, out);

                    ret = xmlTextWriterWriteFormatElement(
                        writer, (xmlChar *)"timeTaken", "%f", time_taken);
                    XML_RET_CHECK_AND_GOTO(ret, out);
                }

                break;

            default:
                ret = -1;
                goto out;
        }

        for (j = 1; j <= members; j++) {
            if (top_op == GF_CLI_TOP_READ_PERF ||
                top_op == GF_CLI_TOP_WRITE_PERF) {
                ret = cli_xml_output_vol_top_rw_perf(writer, dict, i, j);
            } else {
                ret = cli_xml_output_vol_top_other(writer, dict, i, j);
            }
            if (ret)
                goto out;
        }

        /* </brick> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </volTop> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
int
cli_xml_output_vol_profile_stats(xmlTextWriterPtr writer, dict_t *dict,
                                 int brick_index, int interval)
{
    int ret = -1;
    uint64_t read_count = 0;
    uint64_t write_count = 0;
    uint64_t hits = 0;
    double avg_latency = 0.0;
    double max_latency = 0.0;
    double min_latency = 0.0;
    uint64_t duration = 0;
    uint64_t total_read = 0;
    uint64_t total_write = 0;
    char key[1024] = {0};
    int i = 0;

    /* <cumulativeStats> || <intervalStats> */
    if (interval == -1)
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"cumulativeStats");
    else
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"intervalStats");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <blockStats> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"blockStats");
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < 32; i++) {
        /* <block> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"block");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"size",
                                              "%" PRIu32, (1U << i));
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%d-%d-read-%" PRIu32, brick_index, interval,
                 (1U << i));
        ret = dict_get_uint64(dict, key, &read_count);
        if (ret)
            read_count = 0;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"reads",
                                              "%" PRIu64, read_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%d-%d-write-%" PRIu32, brick_index,
                 interval, (1U << i));
        ret = dict_get_uint64(dict, key, &write_count);
        if (ret)
            write_count = 0;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"writes",
                                              "%" PRIu64, write_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </block> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </blockStats> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <fopStats> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"fopStats");
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < GF_FOP_MAXVALUE; i++) {
        snprintf(key, sizeof(key), "%d-%d-%d-hits", brick_index, interval, i);
        ret = dict_get_uint64(dict, key, &hits);
        if (ret)
            goto cont;

        snprintf(key, sizeof(key), "%d-%d-%d-avglatency", brick_index, interval,
                 i);
        ret = dict_get_double(dict, key, &avg_latency);
        if (ret)
            goto cont;

        snprintf(key, sizeof(key), "%d-%d-%d-minlatency", brick_index, interval,
                 i);
        ret = dict_get_double(dict, key, &min_latency);
        if (ret)
            goto cont;

        snprintf(key, sizeof(key), "%d-%d-%d-maxlatency", brick_index, interval,
                 i);
        ret = dict_get_double(dict, key, &max_latency);
        if (ret)
            goto cont;

        /* <fop> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"fop");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              gf_fop_list[i]);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hits",
                                              "%" PRIu64, hits);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"avgLatency",
                                              "%f", avg_latency);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"minLatency",
                                              "%f", min_latency);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"maxLatency",
                                              "%f", max_latency);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </fop> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);

    cont:
        hits = 0;
        avg_latency = 0.0;
        min_latency = 0.0;
        max_latency = 0.0;
    }

    for (i = 0; i < GF_UPCALL_FLAGS_MAXVALUE; i++) {
        hits = 0;
        avg_latency = 0.0;
        min_latency = 0.0;
        max_latency = 0.0;

        snprintf(key, sizeof(key), "%d-%d-%d-upcall-hits", brick_index,
                 interval, i);
        ret = dict_get_uint64(dict, key, &hits);
        if (ret)
            continue;

        /* <fop> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"fop");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              gf_fop_list[i]);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hits",
                                              "%" PRIu64, hits);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"avgLatency",
                                              "%f", avg_latency);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"minLatency",
                                              "%f", min_latency);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"maxLatency",
                                              "%f", max_latency);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </fop> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </fopStats> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-%d-duration", brick_index, interval);
    ret = dict_get_uint64(dict, key, &duration);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"duration",
                                          "%" PRIu64, duration);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-%d-total-read", brick_index, interval);
    ret = dict_get_uint64(dict, key, &total_read);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"totalRead",
                                          "%" PRIu64, total_read);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%d-%d-total-write", brick_index, interval);
    ret = dict_get_uint64(dict, key, &total_write);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"totalWrite",
                                          "%" PRIu64, total_write);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </cumulativeStats> || </intervalStats> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_vol_profile(dict_t *dict, int op_ret, int op_errno,
                           char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    char *volname = NULL;
    int op = GF_CLI_STATS_NONE;
    int info_op = GF_CLI_INFO_NONE;
    int brick_count = 0;
    char *brick_name = NULL;
    int interval = 0;
    char key[1024] = {
        0,
    };
    int i = 0;
    int stats_cleared = 0;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <volProfile> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volProfile");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "volname", &volname);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"volname", "%s",
                                          volname);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "op", &op);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"profileOp", "%d",
                                          op);
    XML_RET_CHECK_AND_GOTO(ret, out);

    if (GF_CLI_STATS_INFO != op)
        goto cont;

    ret = dict_get_int32(dict, "count", &brick_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"brickCount", "%d",
                                          brick_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "info-op", &info_op);
    if (ret)
        goto out;

    while (i < brick_count) {
        i++;

        /* <brick> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"brick");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%d-brick", i);
        ret = dict_get_str(dict, key, &brick_name);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"brickName",
                                              "%s", brick_name);
        XML_RET_CHECK_AND_GOTO(ret, out);

        if (GF_CLI_INFO_CLEAR == info_op) {
            snprintf(key, sizeof(key), "%d-stats-cleared", i);
            ret = dict_get_int32(dict, key, &stats_cleared);
            if (ret)
                goto out;

            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"clearStats", "%s",
                stats_cleared ? "Cleared stats." : "Failed to clear stats.");
            XML_RET_CHECK_AND_GOTO(ret, out);
        } else {
            snprintf(key, sizeof(key), "%d-cumulative", i);
            ret = dict_get_int32(dict, key, &interval);
            if (ret == 0) {
                ret = cli_xml_output_vol_profile_stats(writer, dict, i,
                                                       interval);
                if (ret)
                    goto out;
            }

            snprintf(key, sizeof(key), "%d-interval", i);
            ret = dict_get_int32(dict, key, &interval);
            if (ret == 0) {
                ret = cli_xml_output_vol_profile_stats(writer, dict, i,
                                                       interval);
                if (ret)
                    goto out;
            }
        }

        /* </brick> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

cont:
    /* </volProfile> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(writer, doc);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_list(dict_t *dict, int op_ret, int op_errno, char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    int count = 0;
    char *volname = NULL;
    char key[1024] = {
        0,
    };
    int i = 0;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <volList> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volList");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "count", &count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
                                          count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < count; i++) {
        snprintf(key, sizeof(key), "volume%d", i);
        ret = dict_get_str(dict, key, &volname);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"volume", "%s",
                                              volname);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </volList> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(writer, doc);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
int
cli_xml_output_vol_info_option(xmlTextWriterPtr writer, char *substr,
                               char *optstr, char *valstr)
{
    int ret = -1;
    char *ptr1 = NULL;
    char *ptr2 = NULL;

    ptr1 = substr;
    ptr2 = optstr;

    while (ptr1) {
        if (*ptr1 != *ptr2)
            break;
        ptr1++;
        ptr2++;
        if (!*ptr1)
            break;
        if (!*ptr2)
            break;
    }
    if (*ptr2 == '\0')
        goto out;

    /* <option> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"option");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          ptr2);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"value", "%s",
                                          valstr);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </option> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}

struct tmp_xml_option_logger {
    char *key;
    xmlTextWriterPtr writer;
};

static int
_output_vol_info_option(dict_t *d, char *k, data_t *v, void *data)
{
    int ret = 0;
    char *ptr = NULL;
    struct tmp_xml_option_logger *tmp = NULL;

    tmp = data;

    ptr = strstr(k, "option.");
    if (!ptr)
        goto out;

    if (!v) {
        ret = -1;
        goto out;
    }
    ret = cli_xml_output_vol_info_option(tmp->writer, tmp->key, k, v->data);

out:
    return ret;
}

int
cli_xml_output_vol_info_options(xmlTextWriterPtr writer, dict_t *dict,
                                char *prefix)
{
    int ret = -1;
    int opt_count = 0;
    char key[1024] = {
        0,
    };
    struct tmp_xml_option_logger tmp = {
        0,
    };

    snprintf(key, sizeof(key), "%s.opt_count", prefix);
    ret = dict_get_int32(dict, key, &opt_count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"optCount", "%d",
                                          opt_count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <options> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"options");
    XML_RET_CHECK_AND_GOTO(ret, out);
    snprintf(key, sizeof(key), "%s.option.", prefix);

    tmp.key = key;
    tmp.writer = writer;
    ret = dict_foreach(dict, _output_vol_info_option, &tmp);
    if (ret)
        goto out;

    /* </options> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_vol_info(cli_local_t *local, dict_t *dict)
{
#if (HAVE_LIB_XML)
    int ret = 0;
    int count = 0;
    char *volname = NULL;
    char *volume_id = NULL;
    char *uuid = NULL;
    int type = 0;
    int status = 0;
    int brick_count = 0;
    int dist_count = 0;
    int replica_count = 0;
    int arbiter_count = 0;
    int snap_count = 0;
    int isArbiter = 0;
    int disperse_count = 0;
    int redundancy_count = 0;
    int transport = 0;
    char *brick = NULL;
    char key[1024] = {
        0,
    };
    int i = 0;
    int j = 1;
    char *caps __attribute__((unused)) = NULL;
    int k __attribute__((unused)) = 0;

    ret = dict_get_int32(dict, "count", &count);
    if (ret)
        goto out;

    for (i = 0; i < count; i++) {
        /* <volume> */
        ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volume");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.name", i);
        ret = dict_get_str(dict, key, &volname);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"name",
                                              "%s", volname);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.volume_id", i);
        ret = dict_get_str(dict, key, &volume_id);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"id",
                                              "%s", volume_id);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.status", i);
        ret = dict_get_int32(dict, key, &status);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"status", "%d", status);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(local->writer,
                                              (xmlChar *)"statusStr", "%s",
                                              cli_vol_status_str[status]);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.snap_count", i);
        ret = dict_get_int32(dict, key, &snap_count);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"snapshotCount", "%d", snap_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.brick_count", i);
        ret = dict_get_int32(dict, key, &brick_count);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"brickCount", "%d", brick_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.dist_count", i);
        ret = dict_get_int32(dict, key, &dist_count);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(local->writer,
                                              (xmlChar *)"distCount", "%d",
                                              (brick_count / dist_count));
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.replica_count", i);
        ret = dict_get_int32(dict, key, &replica_count);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"replicaCount", "%d", replica_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.arbiter_count", i);
        ret = dict_get_int32(dict, key, &arbiter_count);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"arbiterCount", "%d", arbiter_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.disperse_count", i);
        ret = dict_get_int32(dict, key, &disperse_count);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"disperseCount", "%d", disperse_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.redundancy_count", i);
        ret = dict_get_int32(dict, key, &redundancy_count);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(local->writer,
                                              (xmlChar *)"redundancyCount",
                                              "%d", redundancy_count);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.type", i);
        ret = dict_get_int32(dict, key, &type);
        if (ret)
            goto out;
        /* For Distributed-(replicate,disperse)
           types
         */
        type = get_vol_type(type, dist_count, brick_count);

        ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"type",
                                              "%d", type);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"typeStr", "%s", vol_type_str[type]);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d.transport", i);
        ret = dict_get_int32(dict, key, &transport);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(
            local->writer, (xmlChar *)"transport", "%d", transport);
        XML_RET_CHECK_AND_GOTO(ret, out);

        j = 1;

        /* <bricks> */
        ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"bricks");
        XML_RET_CHECK_AND_GOTO(ret, out);

        while (j <= brick_count) {
            ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"brick");
            XML_RET_CHECK_AND_GOTO(ret, out);

            snprintf(key, sizeof(key), "volume%d.brick%d.uuid", i, j);
            ret = dict_get_str(dict, key, &uuid);
            if (ret)
                goto out;
            ret = xmlTextWriterWriteFormatAttribute(
                local->writer, (xmlChar *)"uuid", "%s", uuid);
            XML_RET_CHECK_AND_GOTO(ret, out);

            snprintf(key, sizeof(key), "volume%d.brick%d", i, j);
            ret = dict_get_str(dict, key, &brick);
            if (ret)
                goto out;
            ret = xmlTextWriterWriteFormatString(local->writer, "%s", brick);
            XML_RET_CHECK_AND_GOTO(ret, out);

            ret = xmlTextWriterWriteFormatElement(
                local->writer, (xmlChar *)"name", "%s", brick);
            XML_RET_CHECK_AND_GOTO(ret, out);

            ret = xmlTextWriterWriteFormatElement(
                local->writer, (xmlChar *)"hostUuid", "%s", uuid);
            XML_RET_CHECK_AND_GOTO(ret, out);

            snprintf(key, sizeof(key), "volume%d.brick%d.isArbiter", i, j);
            if (dict_get(dict, key))
                isArbiter = 1;
            else
                isArbiter = 0;
            ret = xmlTextWriterWriteFormatElement(
                local->writer, (xmlChar *)"isArbiter", "%d", isArbiter);
            XML_RET_CHECK_AND_GOTO(ret, out);

            /* </brick> */
            ret = xmlTextWriterEndElement(local->writer);
            XML_RET_CHECK_AND_GOTO(ret, out);

            j++;
        }
        /* </bricks> */
        ret = xmlTextWriterEndElement(local->writer);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "volume%d", i);
        ret = cli_xml_output_vol_info_options(local->writer, dict, key);
        if (ret)
            goto out;

        /* </volume> */
        ret = xmlTextWriterEndElement(local->writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    if (volname) {
        GF_FREE(local->get_vol.volname);
        local->get_vol.volname = gf_strdup(volname);
        local->vol_count += count;
    }
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_info_begin(cli_local_t *local, int op_ret, int op_errno,
                              char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    GF_ASSERT(local);

    ret = cli_begin_xml_output(&(local->writer), &(local->doc));
    if (ret)
        goto out;

    ret = cli_xml_output_common(local->writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <volInfo> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volInfo");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <volumes> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volumes");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* Init vol count */
    local->vol_count = 0;

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_info_end(cli_local_t *local)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    GF_ASSERT(local);

    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"count",
                                          "%d", local->vol_count);
    XML_RET_CHECK_AND_GOTO(ret, out);
    /* </volumes> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </volInfo> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(local->writer, local->doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_quota_limit_list_end(cli_local_t *local)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(local->writer, local->doc);

out:
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_quota_limit_list_begin(cli_local_t *local, int op_ret,
                                          int op_errno, char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    ret = cli_begin_xml_output(&(local->writer), &(local->doc));
    if (ret)
        goto out;

    ret = cli_xml_output_common(local->writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <volQuota> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volQuota");
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
static int
cli_xml_output_peer_hostnames(xmlTextWriterPtr writer, dict_t *dict,
                              const char *prefix, int count)
{
    int ret = -1;
    int i = 0;
    char *hostname = NULL;
    char key[1024] = {
        0,
    };

    /* <hostnames> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"hostnames");
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 0; i < count; i++) {
        ret = snprintf(key, sizeof(key), "%s.hostname%d", prefix, i);
        if (ret < 0)
            goto out;
        ret = dict_get_str(dict, key, &hostname);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hostname",
                                              "%s", hostname);
        XML_RET_CHECK_AND_GOTO(ret, out);
        hostname = NULL;
    }

    /* </hostnames> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_peer_status(dict_t *dict, int op_ret, int op_errno,
                           char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    int count = 0;
    char *uuid = NULL;
    char *hostname = NULL;
    int connected = 0;
    int state_id = 0;
    char *state_str = NULL;
    int hostname_count = 0;
    int i = 1;
    char key[1024] = {
        0,
    };

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <peerStatus> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"peerStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    if (!dict)
        goto cont;

    ret = dict_get_int32(dict, "count", &count);
    if (ret)
        goto out;

    while (i <= count) {
        /* <peer> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"peer");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "friend%d.uuid", i);
        ret = dict_get_str(dict, key, &uuid);
        if (ret)
            goto out;

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                              uuid);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "friend%d.hostname", i);
        ret = dict_get_str(dict, key, &hostname);
        if (ret)
            goto out;

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hostname",
                                              "%s", hostname);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "friend%d.hostname_count", i);
        ret = dict_get_int32(dict, key, &hostname_count);
        if ((ret == 0) && (hostname_count > 0)) {
            snprintf(key, sizeof(key), "friend%d", i);
            ret = cli_xml_output_peer_hostnames(writer, dict, key,
                                                hostname_count);
            XML_RET_CHECK_AND_GOTO(ret, out);
        }

        snprintf(key, sizeof(key), "friend%d.connected", i);
        ret = dict_get_int32(dict, key, &connected);
        if (ret)
            goto out;

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"connected",
                                              "%d", connected);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "friend%d.stateId", i);
        ret = dict_get_int32(dict, key, &state_id);
        if (!ret) {
            /* ignore */

            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"state",
                                                  "%d", state_id);
            XML_RET_CHECK_AND_GOTO(ret, out);
        }

        snprintf(key, sizeof(key), "friend%d.state", i);
        ret = dict_get_str(dict, key, &state_str);
        if (!ret) {
            /* ignore */

            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"stateStr",
                                                  "%s", state_str);
            XML_RET_CHECK_AND_GOTO(ret, out);
        }

        /* </peer> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);

        i++;
    }

cont:
    /* </peerStatus> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
/* Used for rebalance stop/status, remove-brick status */
int
cli_xml_output_vol_rebalance_status(xmlTextWriterPtr writer, dict_t *dict,
                                    enum gf_task_types task_type)
{
    int ret = -1;
    int count = 0;
    char *node_name = NULL;
    char *node_uuid = NULL;
    uint64_t files = 0;
    uint64_t size = 0;
    uint64_t lookups = 0;
    int status_rcd = 0;
    uint64_t failures = 0;
    uint64_t skipped = 0;
    uint64_t total_files = 0;
    uint64_t total_size = 0;
    uint64_t total_lookups = 0;
    uint64_t total_failures = 0;
    uint64_t total_skipped = 0;
    char key[1024] = {
        0,
    };
    int i = 0;
    int overall_status = -1;
    double elapsed = 0;
    double overall_elapsed = 0;

    if (!dict) {
        ret = 0;
        goto out;
    }

    ret = dict_get_int32(dict, "count", &count);
    if (ret)
        goto out;
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"nodeCount", "%d",
                                          count);
    XML_RET_CHECK_AND_GOTO(ret, out);

    while (i < count) {
        i++;
        /* Getting status early, to skip nodes that don't have the
         * rebalance process started
         */
        snprintf(key, sizeof(key), "status-%d", i);
        ret = dict_get_int32(dict, key, &status_rcd);

        /* If glusterd is down it fails to get the status, try
         getting status from other nodes */
        if (ret)
            continue;
        if (GF_DEFRAG_STATUS_NOT_STARTED == status_rcd)
            continue;

        /* <node> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"node");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "node-name-%d", i);
        ret = dict_get_str(dict, key, &node_name);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"nodeName",
                                              "%s", node_name);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "node-uuid-%d", i);
        ret = dict_get_str(dict, key, &node_uuid);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"id", "%s",
                                              node_uuid);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "files-%d", i);
        ret = dict_get_uint64(dict, key, &files);
        if (ret)
            goto out;
        total_files += files;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"files",
                                              "%" PRIu64, files);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "size-%d", i);
        ret = dict_get_uint64(dict, key, &size);
        if (ret)
            goto out;
        total_size += size;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"size",
                                              "%" PRIu64, size);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "lookups-%d", i);
        ret = dict_get_uint64(dict, key, &lookups);
        if (ret)
            goto out;
        total_lookups += lookups;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"lookups",
                                              "%" PRIu64, lookups);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "failures-%d", i);
        ret = dict_get_uint64(dict, key, &failures);
        if (ret)
            goto out;

        snprintf(key, sizeof(key), "skipped-%d", i);

        ret = dict_get_uint64(dict, key, &skipped);
        if (ret)
            goto out;

        if (task_type == GF_TASK_TYPE_REMOVE_BRICK) {
            failures += skipped;
            skipped = 0;
        }

        total_failures += failures;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"failures",
                                              "%" PRIu64, failures);
        XML_RET_CHECK_AND_GOTO(ret, out);

        total_skipped += skipped;

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"skipped",
                                              "%" PRIu64, skipped);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status", "%d",
                                              status_rcd);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(
            writer, (xmlChar *)"statusStr", "%s",
            cli_vol_task_status_str[status_rcd]);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "run-time-%d", i);
        ret = dict_get_double(dict, key, &elapsed);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"runtime",
                                              "%.2f", elapsed);
        XML_RET_CHECK_AND_GOTO(ret, out);

        if (elapsed > overall_elapsed) {
            overall_elapsed = elapsed;
        }

        /* Rebalance has 5 states,
         * NOT_STARTED, STARTED, STOPPED, COMPLETE, FAILED
         * The precedence used to determine the aggregate status is as
         * below,
         * STARTED > FAILED > STOPPED > COMPLETE > NOT_STARTED
         */
        /* TODO: Move this to a common place utilities that both CLI and
         * glusterd need.
         * Till then if the below algorithm is changed, change it in
         * glusterd_volume_status_aggregate_tasks_status in
         * glusterd-utils.c
         */

        if (-1 == overall_status)
            overall_status = status_rcd;
        int rank[] = {[GF_DEFRAG_STATUS_STARTED] = 1,
                      [GF_DEFRAG_STATUS_FAILED] = 2,
                      [GF_DEFRAG_STATUS_STOPPED] = 3,
                      [GF_DEFRAG_STATUS_COMPLETE] = 4,
                      [GF_DEFRAG_STATUS_NOT_STARTED] = 5};
        if (rank[status_rcd] <= rank[overall_status])
            overall_status = status_rcd;

        /* </node> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* Aggregate status */
    /* <aggregate> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"aggregate");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"files",
                                          "%" PRIu64, total_files);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"size", "%" PRIu64,
                                          total_size);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"lookups",
                                          "%" PRIu64, total_lookups);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"failures",
                                          "%" PRIu64, total_failures);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"skipped",
                                          "%" PRIu64, total_skipped);
    XML_RET_CHECK_AND_GOTO(ret, out);

    if (overall_status == -1) {
        overall_status = status_rcd;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status", "%d",
                                          overall_status);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        writer, (xmlChar *)"statusStr", "%s",
        cli_vol_task_status_str[overall_status]);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"runtime", "%.2f",
                                          overall_elapsed);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </aggregate> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_vol_rebalance(gf_cli_defrag_type op, dict_t *dict, int op_ret,
                             int op_errno, char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    char *task_id_str = NULL;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <volRebalance> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volRebalance");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, GF_REBALANCE_TID_KEY, &task_id_str);
    if (ret == 0) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"task-id",
                                              "%s", task_id_str);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"op", "%d", op);
    XML_RET_CHECK_AND_GOTO(ret, out);

    if ((GF_DEFRAG_CMD_STOP == op) || (GF_DEFRAG_CMD_STATUS == op)) {
        ret = cli_xml_output_vol_rebalance_status(writer, dict,
                                                  GF_TASK_TYPE_REBALANCE);
        if (ret)
            goto out;
    }

    /* </volRebalance> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_remove_brick(gf_boolean_t status_op, dict_t *dict,
                                int op_ret, int op_errno, char *op_errstr,
                                const char *op)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    char *task_id_str = NULL;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    ret = xmlTextWriterStartElement(writer, (xmlChar *)op);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, GF_REMOVE_BRICK_TID_KEY, &task_id_str);
    if (ret == 0) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"task-id",
                                              "%s", task_id_str);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    if (status_op) {
        ret = cli_xml_output_vol_rebalance_status(writer, dict,
                                                  GF_TASK_TYPE_REMOVE_BRICK);
        if (ret)
            goto out;
    }

    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_replace_brick(dict_t *dict, int op_ret, int op_errno,
                                 char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_vol_create(dict_t *dict, int op_ret, int op_errno,
                          char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    char *volname = NULL;
    char *volid = NULL;

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    if (dict) {
        /* <volCreate> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"volCreate");
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* <volume> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = dict_get_str(dict, "volname", &volname);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              volname);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = dict_get_str(dict, "volume-id", &volid);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"id", "%s",
                                              volid);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </volume> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </volCreate> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_generic_volume(char *op, dict_t *dict, int op_ret, int op_errno,
                              char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    char *volname = NULL;
    char *volid = NULL;

    GF_ASSERT(op);

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    if (dict) {
        /* <"op"> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)op);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* <volume> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = dict_get_str(dict, "volname", &volname);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              volname);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = dict_get_str(dict, "vol-id", &volid);
        if (ret)
            goto out;
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"id", "%s",
                                              volid);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </volume> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </"op"> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
int
_output_gsync_config(FILE *fp, xmlTextWriterPtr writer, char *op_name)
{
    char resbuf[256 + PATH_MAX] = {
        0,
    };
    char *ptr = NULL;
    char *v = NULL;
    int blen = sizeof(resbuf);
    int ret = 0;

    for (;;) {
        ptr = fgets(resbuf, blen, fp);
        if (!ptr)
            break;

        v = resbuf + strlen(resbuf) - 1;
        while (isspace(*v)) {
            /* strip trailing space */
            *v-- = '\0';
        }
        if (v == resbuf) {
            /* skip empty line */
            continue;
        }

        if (op_name != NULL) {
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)op_name,
                                                  "%s", resbuf);
            XML_RET_CHECK_AND_GOTO(ret, out);
            goto out;
        }

        v = strchr(resbuf, ':');
        if (!v) {
            ret = -1;
            goto out;
        }
        *v++ = '\0';
        while (isspace(*v))
            v++;
        v = gf_strdup(v);
        if (!v) {
            ret = -1;
            goto out;
        }

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)resbuf, "%s",
                                              v);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

#if (HAVE_LIB_XML)
int
get_gsync_config(runner_t *runner,
                 int (*op_conf)(FILE *fp, xmlTextWriterPtr writer,
                                char *op_name),
                 xmlTextWriterPtr writer, char *op_name)
{
    int ret = 0;

    runner_redir(runner, STDOUT_FILENO, RUN_PIPE);
    if (runner_start(runner) != 0) {
        gf_log("cli", GF_LOG_ERROR, "spawning child failed");
        return -1;
    }

    ret = op_conf(runner_chio(runner, STDOUT_FILENO), writer, op_name);

    ret |= runner_end(runner);
    if (ret)
        gf_log("cli", GF_LOG_ERROR, "reading data from child failed");

    return ret ? -1 : 0;
}
#endif

#if (HAVE_LIB_XML)
int
cli_xml_generate_gsync_config(dict_t *dict, xmlTextWriterPtr writer)
{
    runner_t runner = {
        0,
    };
    char *subop = NULL;
    char *gwd = NULL;
    char *secondary = NULL;
    char *confpath = NULL;
    char *primary = NULL;
    char *op_name = NULL;
    int ret = -1;
    char conf_path[PATH_MAX] = "";

    if (dict_get_str(dict, "subop", &subop) != 0) {
        ret = -1;
        goto out;
    }

    if (strcmp(subop, "get") != 0 && strcmp(subop, "get-all") != 0) {
        ret = xmlTextWriterWriteFormatElement(
            writer, (xmlChar *)"message", "%s",
            GEOREP " config updated successfully");
        XML_RET_CHECK_AND_GOTO(ret, out);
        ret = 0;
        goto out;
    }

    if (dict_get_str(dict, "glusterd_workdir", &gwd) != 0 ||
        dict_get_str(dict, "secondary", &secondary) != 0) {
        ret = -1;
        goto out;
    }

    if (dict_get_str(dict, "primary", &primary) != 0)
        primary = NULL;

    if (dict_get_str(dict, "op_name", &op_name) != 0)
        op_name = NULL;

    ret = dict_get_str(dict, "conf_path", &confpath);
    if (!confpath) {
        ret = snprintf(conf_path, sizeof(conf_path) - 1,
                       "%s/" GEOREP "/gsyncd_template.conf", gwd);
        conf_path[ret] = '\0';
        confpath = conf_path;
    }

    runinit(&runner);
    runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "-c", NULL);
    runner_argprintf(&runner, "%s", confpath);
    runner_argprintf(&runner, "--iprefix=%s", DATADIR);

    if (primary)
        runner_argprintf(&runner, ":%s", primary);

    runner_add_arg(&runner, secondary);
    runner_argprintf(&runner, "--config-%s", subop);

    if (op_name)
        runner_add_arg(&runner, op_name);

    ret = get_gsync_config(&runner, _output_gsync_config, writer, op_name);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

#if (HAVE_LIB_XML)
int
cli_xml_output_vol_gsync_status(dict_t *dict, xmlTextWriterPtr writer)
{
    int ret = -1;
    int i = 1;
    int j = 0;
    int count = 0;
    const int number_of_fields = 20;
    int closed = 1;
    int session_closed = 1;
    gf_gsync_status_t **status_values = NULL;
    char status_value_name[PATH_MAX] = "";
    char *tmp = NULL;
    char *volume = NULL;
    char *volume_next = NULL;
    char *secondary = NULL;
    char *secondary_next = NULL;
    static const char *title_values[] = {
        "primary_node", "", "primary_brick", "secondary_user", "secondary",
        "secondary_node", "status", "crawl_status",
        /* last_synced */
        "", "entry", "data", "meta", "failures",
        /* checkpoint_time */
        "", "checkpoint_completed",
        /* checkpoint_completion_time */
        "", "primary_node_uuid",
        /* last_synced_utc */
        "last_synced",
        /* checkpoint_time_utc */
        "checkpoint_time",
        /* checkpoint_completion_time_utc */
        "checkpoint_completion_time"};

    GF_ASSERT(dict);

    ret = dict_get_int32(dict, "gsync-count", &count);
    if (ret)
        goto out;

    status_values = GF_MALLOC(count * sizeof(gf_gsync_status_t *),
                              gf_common_mt_char);
    if (!status_values) {
        ret = -1;
        goto out;
    }

    for (i = 0; i < count; i++) {
        status_values[i] = GF_CALLOC(1, sizeof(gf_gsync_status_t),
                                     gf_common_mt_char);
        if (!status_values[i]) {
            ret = -1;
            goto out;
        }

        snprintf(status_value_name, sizeof(status_value_name), "status_value%d",
                 i);

        ret = dict_get_bin(dict, status_value_name,
                           (void **)&(status_values[i]));
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "struct member empty.");
            goto out;
        }
    }

    qsort(status_values, count, sizeof(gf_gsync_status_t *),
          gf_gsync_status_t_comparator);

    for (i = 0; i < count; i++) {
        if (closed) {
            ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
            XML_RET_CHECK_AND_GOTO(ret, out);

            tmp = get_struct_variable(1, status_values[i]);
            if (!tmp) {
                gf_log("cli", GF_LOG_ERROR, "struct member empty.");
                ret = -1;
                goto out;
            }

            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name",
                                                  "%s", tmp);
            XML_RET_CHECK_AND_GOTO(ret, out);

            ret = xmlTextWriterStartElement(writer, (xmlChar *)"sessions");
            XML_RET_CHECK_AND_GOTO(ret, out);

            closed = 0;
        }

        if (session_closed) {
            ret = xmlTextWriterStartElement(writer, (xmlChar *)"session");
            XML_RET_CHECK_AND_GOTO(ret, out);

            session_closed = 0;

            tmp = get_struct_variable(21, status_values[i]);
            if (!tmp) {
                gf_log("cli", GF_LOG_ERROR, "struct member empty.");
                ret = -1;
                goto out;
            }

            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"session_secondary", "%s", tmp);
            XML_RET_CHECK_AND_GOTO(ret, out);
        }

        ret = xmlTextWriterStartElement(writer, (xmlChar *)"pair");
        XML_RET_CHECK_AND_GOTO(ret, out);

        for (j = 0; j < number_of_fields; j++) {
            /* XML ignore fields */
            if (strcmp(title_values[j], "") == 0)
                continue;

            tmp = get_struct_variable(j, status_values[i]);
            if (!tmp) {
                gf_log("cli", GF_LOG_ERROR, "struct member empty.");
                ret = -1;
                goto out;
            }

            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)title_values[j], "%s", tmp);
            XML_RET_CHECK_AND_GOTO(ret, out);
        }

        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);

        if (i + 1 < count) {
            secondary = get_struct_variable(20, status_values[i]);
            secondary_next = get_struct_variable(20, status_values[i + 1]);
            volume = get_struct_variable(1, status_values[i]);
            volume_next = get_struct_variable(1, status_values[i + 1]);
            if (!secondary || !secondary_next || !volume || !volume_next) {
                gf_log("cli", GF_LOG_ERROR, "struct member empty.");
                ret = -1;
                goto out;
            }

            if (strcmp(volume, volume_next) != 0) {
                closed = 1;
                session_closed = 1;

                ret = xmlTextWriterEndElement(writer);
                XML_RET_CHECK_AND_GOTO(ret, out);

                ret = xmlTextWriterEndElement(writer);
                XML_RET_CHECK_AND_GOTO(ret, out);

                ret = xmlTextWriterEndElement(writer);
                XML_RET_CHECK_AND_GOTO(ret, out);
            } else if (strcmp(secondary, secondary_next) != 0) {
                session_closed = 1;

                ret = xmlTextWriterEndElement(writer);
                XML_RET_CHECK_AND_GOTO(ret, out);
            }
        } else {
            ret = xmlTextWriterEndElement(writer);
            XML_RET_CHECK_AND_GOTO(ret, out);

            ret = xmlTextWriterEndElement(writer);
            XML_RET_CHECK_AND_GOTO(ret, out);

            ret = xmlTextWriterEndElement(writer);
            XML_RET_CHECK_AND_GOTO(ret, out);
        }
    }
out:
    if (status_values)
        GF_FREE(status_values);
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
}
#endif

int
cli_xml_output_vol_gsync(dict_t *dict, int op_ret, int op_errno,
                         char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    char *primary = NULL;
    char *secondary = NULL;
    int type = 0;

    GF_ASSERT(dict);

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    /* <geoRep> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"geoRep");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "type", &type);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get type");
        goto out;
    }

    switch (type) {
        case GF_GSYNC_OPTION_TYPE_START:
        case GF_GSYNC_OPTION_TYPE_STOP:
        case GF_GSYNC_OPTION_TYPE_PAUSE:
        case GF_GSYNC_OPTION_TYPE_RESUME:
        case GF_GSYNC_OPTION_TYPE_CREATE:
        case GF_GSYNC_OPTION_TYPE_DELETE:
            if (dict_get_str(dict, "primary", &primary) != 0)
                primary = "???";
            if (dict_get_str(dict, "secondary", &secondary) != 0)
                secondary = "???";

            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"primary",
                                                  "%s", primary);
            XML_RET_CHECK_AND_GOTO(ret, out);

            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"secondary", "%s", secondary);
            XML_RET_CHECK_AND_GOTO(ret, out);

            break;

        case GF_GSYNC_OPTION_TYPE_CONFIG:
            if (op_ret == 0) {
                ret = xmlTextWriterStartElement(writer, (xmlChar *)"config");
                XML_RET_CHECK_AND_GOTO(ret, out);

                ret = cli_xml_generate_gsync_config(dict, writer);
                if (ret)
                    goto out;

                ret = xmlTextWriterEndElement(writer);
                XML_RET_CHECK_AND_GOTO(ret, out);
            }

            break;
        case GF_GSYNC_OPTION_TYPE_STATUS:
            ret = cli_xml_output_vol_gsync_status(dict, writer);
            if (ret) {
                gf_log("cli", GF_LOG_DEBUG, "Failed to get gsync status");
                goto out;
            }
            break;
        default:
            ret = 0;
            break;
    }

    /* </geoRep> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(writer, doc);
out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

#if (HAVE_LIB_XML)
/* This function will generate snapshot create output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing create output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_create(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
{
    int ret = -1;
    char *str_value = NULL;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <snapCreate> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapCreate");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapshot> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapname", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapuuid", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapshot> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapCreate> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:
    return ret;
}

/* This function will generate snapshot clone output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing create output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_clone(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
{
    int ret = -1;
    char *str_value = NULL;

    GF_VALIDATE_OR_GOTO("cli", writer, out);
    GF_VALIDATE_OR_GOTO("cli", doc, out);
    GF_VALIDATE_OR_GOTO("cli", dict, out);

    /* <CloneCreate> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"CloneCreate");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <volume> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "clonename", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get clone name");
        goto out;
    }
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapuuid", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get clone uuid");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </volume> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </CloneCreate> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:
    return ret;
}

/* This function will generate snapshot restore output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing restore output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_restore(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
{
    int ret = -1;
    char *str_value = NULL;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <snapRestore> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapRestore");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <volume> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "volname", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get vol name");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "volid", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get volume id");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </volume> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapshot> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapname", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapuuid", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapshot> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapRestore> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:

    return ret;
}

/* This function will generate snapshot list output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing list output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_list(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
{
    int ret = -1;
    int i = 0;
    int snapcount = 0;
    char *str_value = NULL;
    char key[PATH_MAX] = "";

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <snapList> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapList");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "snapcount", &snapcount);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snapcount");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
                                          snapcount);
    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 1; i <= snapcount; ++i) {
        ret = snprintf(key, sizeof(key), "snapname%d", i);
        if (ret < 0) {
            goto out;
        }

        ret = dict_get_str(dict, key, &str_value);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Could not get %s ", key);
            goto out;
        } else {
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"snapshot",
                                                  "%s", str_value);
            XML_RET_CHECK_AND_GOTO(ret, out);
        }
    }

    /* </snapList> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:

    return ret;
}

/* This function will generate xml output for origin volume
 * of the given snapshot.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing info output
 * @param keyprefix     prefix for dictionary key
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_info_orig_vol(xmlTextWriterPtr writer, xmlDocPtr doc,
                               dict_t *dict, char *keyprefix)
{
    int ret = -1;
    int value = 0;
    char *buffer = NULL;
    char key[PATH_MAX] = "";

    GF_ASSERT(dict);
    GF_ASSERT(keyprefix);
    GF_ASSERT(writer);
    GF_ASSERT(doc);

    /* <originVolume> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"originVolume");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%sorigin-volname", keyprefix);

    ret = dict_get_str(dict, key, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_WARNING, "Failed to get %s", key);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%ssnapcount", keyprefix);

    ret = dict_get_int32(dict, key, &value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"snapCount", "%d",
                                          value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%ssnaps-available", keyprefix);

    ret = dict_get_int32(dict, key, &value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"snapRemaining",
                                          "%d", value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </originVolume> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:
    return ret;
}

/* This function will generate xml output of snapshot volume info.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing info output
 * @param keyprefix     key prefix for dictionary
 * @param snap_driven   boolean to check if output is based of volume
 *                      or snapshot
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_info_snap_vol(xmlTextWriterPtr writer, xmlDocPtr doc,
                               dict_t *dict, char *keyprefix,
                               gf_boolean_t snap_driven)
{
    char key[PATH_MAX] = "";
    char *buffer = NULL;
    int ret = -1;

    GF_ASSERT(dict);
    GF_ASSERT(keyprefix);
    GF_ASSERT(writer);
    GF_ASSERT(doc);

    /* <snapVolume> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapVolume");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = snprintf(key, sizeof(key), "%s.volname", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_str(dict, key, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = snprintf(key, sizeof(key), "%s.vol-status", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_str(dict, key, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* If the command is snap_driven then we need to show origin volume
     * info. Else this is shown in the start of info display.*/
    if (snap_driven) {
        ret = snprintf(key, sizeof(key), "%s.", keyprefix);
        if (ret < 0)
            goto out;

        ret = cli_xml_snapshot_info_orig_vol(writer, doc, dict, key);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR,
                   "Failed to create "
                   "xml output for snapshot's origin volume");
            goto out;
        }
    }

    /* </snapVolume> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:
    return ret;
}

/* This function will generate snapshot info of individual snapshot
 * in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing info output
 * @param keyprefix     key prefix for dictionary
 * @param snap_driven   boolean to check if output is based of volume
 *                      or snapshot
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_info_per_snap(xmlTextWriterPtr writer, xmlDocPtr doc,
                               dict_t *dict, char *keyprefix,
                               gf_boolean_t snap_driven)
{
    char key_buffer[PATH_MAX] = "";
    char *buffer = NULL;
    int volcount = 0;
    int ret = -1;
    int i = 0;

    GF_ASSERT(dict);
    GF_ASSERT(keyprefix);
    GF_ASSERT(writer);
    GF_ASSERT(doc);

    /* <snapshot> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snapname", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_str(dict, key_buffer, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Unable to fetch snapname %s ", key_buffer);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snap-id", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_str(dict, key_buffer, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Unable to fetch snap-id %s ", key_buffer);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snap-desc", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_str(dict, key_buffer, &buffer);
    if (!ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"description",
                                              "%s", buffer);
    } else {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"description",
                                              "%s", "");
    }
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snap-time", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_str(dict, key_buffer, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Unable to fetch snap-time %s ", keyprefix);
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"createTime", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = snprintf(key_buffer, sizeof(key_buffer), "%s.vol-count", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_int32(dict, key_buffer, &volcount);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Fail to get snap vol count");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"volCount", "%d",
                                          volcount);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, key_buffer, &volcount);
    /* Display info of each snapshot volume */
    for (i = 1; i <= volcount; i++) {
        ret = snprintf(key_buffer, sizeof(key_buffer), "%s.vol%d", keyprefix,
                       i);
        if (ret < 0)
            goto out;

        ret = cli_xml_snapshot_info_snap_vol(writer, doc, dict, key_buffer,
                                             snap_driven);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR,
                   "Could not list "
                   "details of volume in a snap");
            goto out;
        }
    }

    /* </snapshot> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);
out:
    return ret;
}

/* This function will generate snapshot info output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing info output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_info(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
{
    int ret = -1;
    int i = 0;
    int snapcount = 0;
    char key[PATH_MAX] = "";
    gf_boolean_t snap_driven = _gf_false;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <snapInfo> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapInfo");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snap_driven = dict_get_str_boolean(dict, "snap-driven", _gf_false);

    /* If the approach is volume based then we should display origin volume
     * information first followed by per snap info*/
    if (!snap_driven) {
        ret = cli_xml_snapshot_info_orig_vol(writer, doc, dict, "");
        if (ret) {
            gf_log("cli", GF_LOG_ERROR,
                   "Failed to create "
                   "xml output for snapshot's origin volume");
            goto out;
        }
    }

    ret = dict_get_int32(dict, "snapcount", &snapcount);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snapcount");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
                                          snapcount);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapshots> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshots");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* Get snapshot info of individual snapshots */
    for (i = 1; i <= snapcount; ++i) {
        snprintf(key, sizeof(key), "snap%d", i);

        ret = cli_xml_snapshot_info_per_snap(writer, doc, dict, key,
                                             snap_driven);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Could not get %s ", key);
            goto out;
        }
    }

    /* </snapshots> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapInfo> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:

    return ret;
}

/* This function will generate snapshot status of individual
 * snapshot volume in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing status output
 * @param keyprefix     key prefix for dictionary
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_volume_status(xmlTextWriterPtr writer, xmlDocPtr doc,
                               dict_t *dict, const char *keyprefix)
{
    int ret = -1;
    int brickcount = 0;
    int i = 0;
    int pid = 0;
    char *buffer = NULL;
    char key[PATH_MAX] = "";

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);
    GF_ASSERT(keyprefix);

    ret = snprintf(key, sizeof(key), "%s.brickcount", keyprefix);
    if (ret < 0)
        goto out;

    ret = dict_get_int32(dict, key, &brickcount);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to fetch brickcount");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"brickCount", "%d",
                                          brickcount);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* Get status of every brick belonging to the snapshot volume */
    for (i = 0; i < brickcount; i++) {
        /* <snapInfo> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"brick");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = snprintf(key, sizeof(key), "%s.brick%d.path", keyprefix, i);
        if (ret < 0)
            goto out;

        ret = dict_get_str(dict, key, &buffer);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Unable to get Brick Path");
            /*
             * If path itself is not present, then end *
             * this brick's status and continue to the *
             * brick                                   *
             */
            ret = xmlTextWriterEndElement(writer);
            XML_RET_CHECK_AND_GOTO(ret, out);
            continue;
        }

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"path", "%s",
                                              buffer);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = snprintf(key, sizeof(key), "%s.brick%d.vgname", keyprefix, i);
        if (ret < 0)
            goto out;

        ret = dict_get_str(dict, key, &buffer);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Unable to get Volume Group");
            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"volumeGroup", "N/A");
        } else
            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"volumeGroup", "%s", buffer);

        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = snprintf(key, sizeof(key), "%s.brick%d.status", keyprefix, i);
        if (ret < 0)
            goto out;

        ret = dict_get_str(dict, key, &buffer);
        if (ret) {
            gf_log("cli", GF_LOG_INFO, "Unable to get Brick Running");
            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"brick_running", "N/A");
        } else
            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"brick_running", "%s", buffer);

        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = snprintf(key, sizeof(key), "%s.brick%d.pid", keyprefix, i);
        if (ret < 0)
            goto out;

        ret = dict_get_int32(dict, key, &pid);
        if (ret) {
            gf_log("cli", GF_LOG_INFO, "Unable to get pid");
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"pid",
                                                  "N/A");
        } else
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"pid",
                                                  "%d", pid);

        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = snprintf(key, sizeof(key), "%s.brick%d.data", keyprefix, i);
        if (ret < 0)
            goto out;

        ret = dict_get_str(dict, key, &buffer);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Unable to get Data Percent");
            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"data_percentage", "N/A");
        } else
            ret = xmlTextWriterWriteFormatElement(
                writer, (xmlChar *)"data_percentage", "%s", buffer);

        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = snprintf(key, sizeof(key), "%s.brick%d.lvsize", keyprefix, i);
        if (ret < 0)
            goto out;

        ret = dict_get_str(dict, key, &buffer);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Unable to get LV Size");
            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"lvSize",
                                                  "N/A");
        } else {
            /* Truncate any newline character */
            buffer = strtok(buffer, "\n");

            ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"lvSize",
                                                  "%s", buffer);
        }

        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </brick> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

out:
    return ret;
}

/* This function will generate snapshot status of individual
 * snapshot in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing status output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_status_per_snap(xmlTextWriterPtr writer, xmlDocPtr doc,
                                 dict_t *dict, const char *keyprefix)
{
    int ret = -1;
    int volcount = 0;
    int i = 0;
    char *buffer = NULL;
    char key[PATH_MAX] = "";

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);
    GF_ASSERT(keyprefix);

    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.snapname", keyprefix);

    ret = dict_get_str(dict, key, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Unable to get snapname");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.uuid", keyprefix);

    ret = dict_get_str(dict, key, &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Unable to get snap UUID");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    snprintf(key, sizeof(key), "%s.volcount", keyprefix);

    ret = dict_get_int32(dict, key, &volcount);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Unable to get volume count");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"volCount", "%d",
                                          volcount);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* Get snapshot status of individual snapshot volume */
    for (i = 0; i < volcount; i++) {
        /* <volume> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(key, sizeof(key), "%s.vol%d", keyprefix, i);

        ret = cli_xml_snapshot_volume_status(writer, doc, dict, key);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Could not get snap volume status");
            goto out;
        }

        /* </volume> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </snapshot> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:
    return ret;
}

/* This function will generate snapshot status output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing status output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_status(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
{
    int ret = -1;
    int snapcount = 0;
    int i = 0;
    int status_cmd = 0;
    char key[PATH_MAX] = "";

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <snapStatus> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "sub-cmd", &status_cmd);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Could not fetch status type");
        goto out;
    }

    if ((GF_SNAP_STATUS_TYPE_SNAP == status_cmd) ||
        (GF_SNAP_STATUS_TYPE_ITER == status_cmd)) {
        snapcount = 1;
    } else {
        ret = dict_get_int32(dict, "status.snapcount", &snapcount);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Could not get snapcount");
            goto out;
        }

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
                                              snapcount);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    for (i = 0; i < snapcount; i++) {
        snprintf(key, sizeof(key), "status.snap%d", i);

        ret = cli_xml_snapshot_status_per_snap(writer, doc, dict, key);
        if (ret < 0) {
            gf_log("cli", GF_LOG_ERROR,
                   "failed to create xml "
                   "output for snapshot status");
            goto out;
        }
    }

    /* </snapStatus> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:

    return ret;
}

/* This function will generate snapshot config show output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing status output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_config_show(xmlTextWriterPtr writer, xmlDocPtr doc,
                             dict_t *dict)
{
    int ret = -1;
    uint64_t i = 0;
    uint64_t value = 0;
    uint64_t volcount = 0;
    char buf[PATH_MAX] = "";
    char *str_value = NULL;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <systemConfig> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"systemConfig");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_uint64(dict, "snap-max-hard-limit", &value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to get "
               "snap-max-hard-limit");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hardLimit",
                                          "%" PRIu64, value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_uint64(dict, "snap-max-soft-limit", &value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to get "
               "snap-max-soft-limit");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"softLimit",
                                          "%" PRIu64 "%%", value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "auto-delete", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Could not fetch auto-delete");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"autoDelete", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snap-activate-on-create", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Could not fetch snap-activate-on-create-delete");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"activateOnCreate",
                                          "%s", str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </systemConfig> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <volumeConfig> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volumeConfig");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_uint64(dict, "voldisplaycount", &volcount);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Could not fetch volcount");
        goto out;
    }

    /* Get config of all the volumes */
    for (i = 0; i < volcount; i++) {
        /* <volume> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(buf, sizeof(buf), "volume%" PRIu64 "-volname", i);
        ret = dict_get_str(dict, buf, &str_value);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
            goto out;
        }

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              str_value);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(buf, sizeof(buf), "volume%" PRIu64 "-snap-max-hard-limit", i);
        ret = dict_get_uint64(dict, buf, &value);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
            goto out;
        }

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hardLimit",
                                              "%" PRIu64, value);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(buf, sizeof(buf), "volume%" PRIu64 "-active-hard-limit", i);
        ret = dict_get_uint64(dict, buf, &value);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR,
                   "Could not fetch"
                   " effective snap_max_hard_limit for "
                   "%s",
                   str_value);
            goto out;
        }

        ret = xmlTextWriterWriteFormatElement(
            writer, (xmlChar *)"effectiveHardLimit", "%" PRIu64, value);
        XML_RET_CHECK_AND_GOTO(ret, out);

        snprintf(buf, sizeof(buf), "volume%" PRIu64 "-snap-max-soft-limit", i);
        ret = dict_get_uint64(dict, buf, &value);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
            goto out;
        }

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"softLimit",
                                              "%" PRIu64, value);
        XML_RET_CHECK_AND_GOTO(ret, out);

        /* </volume> */
        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </volume> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:
    return ret;
}

/* This function will generate snapshot config set output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing status output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_config_set(xmlTextWriterPtr writer, xmlDocPtr doc,
                            dict_t *dict)
{
    int ret = -1;
    uint64_t hard_limit = 0;
    uint64_t soft_limit = 0;
    char *volname = NULL;
    char *auto_delete = NULL;
    char *snap_activate = NULL;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* This is optional parameter therefore ignore the error */
    ret = dict_get_uint64(dict, "snap-max-hard-limit", &hard_limit);
    /* This is optional parameter therefore ignore the error */
    ret = dict_get_uint64(dict, "snap-max-soft-limit", &soft_limit);
    ret = dict_get_str(dict, "auto-delete", &auto_delete);
    ret = dict_get_str(dict, "snap-activate-on-create", &snap_activate);

    if (!hard_limit && !soft_limit && !auto_delete && !snap_activate) {
        ret = -1;
        gf_log("cli", GF_LOG_ERROR,
               "At least one option from "
               "snap-max-hard-limit, snap-max-soft-limit, auto-delete"
               " and snap-activate-on-create should be set");
        goto out;
    }

    /* Ignore the error, as volname is optional */
    ret = dict_get_str(dict, "volname", &volname);

    if (NULL == volname) {
        /* <systemConfig> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"systemConfig");
    } else {
        /* <volumeConfig> */
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"volumeConfig");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                              volname);
    }

    XML_RET_CHECK_AND_GOTO(ret, out);

    if (hard_limit) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"newHardLimit",
                                              "%" PRIu64, hard_limit);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    if (soft_limit) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"newSoftLimit",
                                              "%" PRIu64, soft_limit);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    if (auto_delete) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"autoDelete",
                                              "%s", auto_delete);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    if (snap_activate) {
        ret = xmlTextWriterWriteFormatElement(
            writer, (xmlChar *)"activateOnCreate", "%s", snap_activate);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }

    /* </volumeConfig> or </systemConfig> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:
    return ret;
}

/* This function will generate snapshot config output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing config output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_config(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
{
    int ret = -1;
    int config_command = 0;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <snapConfig> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapConfig");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "config-command", &config_command);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Could not fetch config type");
        goto out;
    }

    switch (config_command) {
        case GF_SNAP_CONFIG_TYPE_SET:
            ret = cli_xml_snapshot_config_set(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create xml "
                       "output for snapshot config set command");
                goto out;
            }

            break;
        case GF_SNAP_CONFIG_DISPLAY:
            ret = cli_xml_snapshot_config_show(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create xml "
                       "output for snapshot config show command");
                goto out;
            }
            break;
        default:
            gf_log("cli", GF_LOG_ERROR, "Unknown config command :%d",
                   config_command);
            ret = -1;
            goto out;
    }

    /* </snapConfig> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:

    return ret;
}

/* This function will generate snapshot activate or
 * deactivate output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing activate or deactivate output
 *
 * @return 0 on success and -1 on failure
 */
static int
cli_xml_snapshot_activate_deactivate(xmlTextWriterPtr writer, xmlDocPtr doc,
                                     dict_t *dict, int cmd)
{
    int ret = -1;
    char *buffer = NULL;
    char *tag = NULL;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    if (GF_SNAP_OPTION_TYPE_ACTIVATE == cmd) {
        tag = "snapActivate";
    } else if (GF_SNAP_OPTION_TYPE_DEACTIVATE == cmd) {
        tag = "snapDeactivate";
    } else {
        gf_log("cli", GF_LOG_ERROR, "invalid command %d", cmd);
        goto out;
    }

    /* <snapActivate> or <snapDeactivate> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)tag);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapshot> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapname", &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapuuid", &buffer);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
        goto out;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          buffer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapshot> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapActivate> or </snapDeactivate> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = 0;
out:

    return ret;
}
#endif /* HAVE_LIB_XML */

/* This function will generate snapshot delete output in xml format.
 *
 * @param writer        xmlTextWriterPtr
 * @param doc           xmlDocPtr
 * @param dict          dict containing delete output
 * @param rsp           cli response
 *
 * @return 0 on success and -1 on failure
 */
int
cli_xml_snapshot_delete(cli_local_t *local, dict_t *dict, gf_cli_rsp *rsp)
{
    int ret = -1;
#ifdef HAVE_LIB_XML
    char *str_value = NULL;
    xmlTextWriterPtr writer = local->writer;
    xmlDocPtr doc = local->doc;

    GF_ASSERT(writer);
    GF_ASSERT(doc);
    GF_ASSERT(dict);

    /* <snapshot> */
    ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_str(dict, "snapname", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
        goto xmlend;
    }

    if (!rsp->op_ret) {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status",
                                              "Success");
    } else {
        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status",
                                              "Failure");
        XML_RET_CHECK_AND_GOTO(ret, xmlend);

        ret = cli_xml_output_common(writer, rsp->op_ret, rsp->op_errno,
                                    rsp->op_errstr);
    }
    XML_RET_CHECK_AND_GOTO(ret, xmlend);

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, xmlend);

    ret = dict_get_str(dict, "snapuuid", &str_value);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
        goto xmlend;
    }

    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
                                          str_value);
    XML_RET_CHECK_AND_GOTO(ret, out);

xmlend:
    /* </snapshot> */
    ret = xmlTextWriterEndElement(writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

#endif /* HAVE_LIB_XML */
    ret = 0;
out:

    return ret;
}

int
cli_xml_output_snap_status_begin(cli_local_t *local, int op_ret, int op_errno,
                                 char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    GF_ASSERT(local);

    ret = cli_begin_xml_output(&(local->writer), &(local->doc));
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_xml_output_common(local->writer, op_ret, op_errno, op_errstr);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapStatus> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapStatus");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapshots> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapshots");
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_snap_status_end(cli_local_t *local)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    GF_ASSERT(local);

    /* </snapshots> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapStatus> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(local->writer, local->doc);
out:
    gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_snap_delete_begin(cli_local_t *local, int op_ret, int op_errno,
                                 char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    int delete_cmd = -1;

    GF_ASSERT(local);

    ret = cli_begin_xml_output(&(local->writer), &(local->doc));
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(local->dict, "sub-cmd", &delete_cmd);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Failed to get sub-cmd");
        goto out;
    }

    ret = cli_xml_output_common(local->writer, op_ret, op_errno, op_errstr);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapStatus> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapDelete");
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* <snapshots> */
    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapshots");
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}

int
cli_xml_output_snap_delete_end(cli_local_t *local)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    GF_ASSERT(local);

    /* </snapshots> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    /* </snapDelete> */
    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = cli_end_xml_output(local->writer, local->doc);
out:
    gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif
}
/* This function will generate xml output for all the snapshot commands
 *
 * @param cmd_type      command type
 * @param dict          dict containing snapshot command output
 * @param op_ret        return value of the snapshot command
 * @param op_errno      errno for the snapshot command
 * @param op_errstr     error string for the snapshot command
 *
 * @return 0 on success and -1 on failure
 */
int
cli_xml_output_snapshot(int cmd_type, dict_t *dict, int op_ret, int op_errno,
                        char *op_errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;

    GF_ASSERT(dict);

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to output "
               "xml begin block");
        goto out;
    }

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to output "
               "xml common block");
        goto out;
    }

    /* In case of command failure just printing the error message is good
     * enough */
    if (0 != op_ret) {
        goto end;
    }

    switch (cmd_type) {
        case GF_SNAP_OPTION_TYPE_CREATE:
            ret = cli_xml_snapshot_create(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create "
                       "xml output for snapshot create command");
                goto out;
            }
            break;
        case GF_SNAP_OPTION_TYPE_CLONE:
            ret = cli_xml_snapshot_clone(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create "
                       "xml output for snapshot clone command");
                goto out;
            }
            break;
        case GF_SNAP_OPTION_TYPE_RESTORE:
            ret = cli_xml_snapshot_restore(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create "
                       "xml output for snapshot restore command");
                goto out;
            }
            break;
        case GF_SNAP_OPTION_TYPE_LIST:
            ret = cli_xml_snapshot_list(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create "
                       "xml output for snapshot list command");
                goto out;
            }
            break;
        case GF_SNAP_OPTION_TYPE_STATUS:
            ret = cli_xml_snapshot_status(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create"
                       "xml output for snapshot status command");
                goto out;
            }
            break;
        case GF_SNAP_OPTION_TYPE_INFO:
            ret = cli_xml_snapshot_info(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create "
                       "xml output for snapshot info command");
                goto out;
            }
            break;
        case GF_SNAP_OPTION_TYPE_ACTIVATE:
        case GF_SNAP_OPTION_TYPE_DEACTIVATE:
            ret = cli_xml_snapshot_activate_deactivate(writer, doc, dict,
                                                       cmd_type);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create "
                       "xml output for snapshot config command");
            }
            break;
        case GF_SNAP_OPTION_TYPE_CONFIG:
            ret = cli_xml_snapshot_config(writer, doc, dict);
            if (ret) {
                gf_log("cli", GF_LOG_ERROR,
                       "Failed to create "
                       "xml output for snapshot config command");
            }
            break;
        default:
            gf_log("cli", GF_LOG_ERROR, "Unexpected snapshot command: %d",
                   cmd_type);
            goto out;
    }

end:
    ret = cli_end_xml_output(writer, doc);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to output "
               "xml end block");
        goto out;
    }

    ret = 0;
out:
    return ret;
#else
    return 0;
#endif /* HAVE_LIB_XML */
}

int
cli_xml_snapshot_begin_composite_op(cli_local_t *local)
{
    int ret = -1;
#ifdef HAVE_LIB_XML
    int cmd = -1;
    int type = -1;

    ret = dict_get_int32(local->dict, "sub-cmd", &cmd);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to get "
               "sub-cmd");
        ret = 0;
        goto out;
    }

    if (cmd == GF_SNAP_STATUS_TYPE_ITER || cmd == GF_SNAP_DELETE_TYPE_SNAP) {
        ret = 0;
        goto out;
    }

    ret = dict_get_int32(local->dict, "type", &type);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to get snapshot "
               "command type from dictionary");
        goto out;
    }

    if (GF_SNAP_OPTION_TYPE_STATUS == type)
        ret = cli_xml_output_snap_status_begin(local, 0, 0, NULL);
    else if (GF_SNAP_OPTION_TYPE_DELETE == type)
        ret = cli_xml_output_snap_delete_begin(local, 0, 0, NULL);

    if (ret) {
        gf_log("cli", GF_LOG_ERROR, "Error creating xml output");
        goto out;
    }

#endif /* HAVE_LIB_XML */
    ret = 0;
out:
    return ret;
}

int
cli_xml_snapshot_end_composite_op(cli_local_t *local)
{
    int ret = -1;
#ifdef HAVE_LIB_XML
    int cmd = -1;
    int type = -1;

    ret = dict_get_int32(local->dict, "sub-cmd", &cmd);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to get "
               "sub-cmd");
        ret = 0;
        goto out;
    }

    if (cmd == GF_SNAP_STATUS_TYPE_ITER || cmd == GF_SNAP_DELETE_TYPE_SNAP) {
        ret = 0;
        goto out;
    }

    ret = dict_get_int32(local->dict, "type", &type);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to get snapshot "
               "command type from dictionary");
        goto out;
    }

    if (GF_SNAP_OPTION_TYPE_STATUS == type)
        ret = cli_xml_output_snap_status_end(local);
    else if (GF_SNAP_OPTION_TYPE_DELETE == type)
        ret = cli_xml_output_snap_delete_end(local);

    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Error creating xml "
               "output");
        goto out;
    }
#endif /* HAVE_LIB_XML */
    ret = 0;
out:
    return ret;
}

int
cli_xml_snapshot_status_single_snap(cli_local_t *local, dict_t *dict, char *key)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    GF_VALIDATE_OR_GOTO("cli", (local != NULL), out);
    GF_VALIDATE_OR_GOTO("cli", (dict != NULL), out);
    GF_VALIDATE_OR_GOTO("cli", (key != NULL), out);

    ret = cli_xml_snapshot_status_per_snap(local->writer, local->doc, dict,
                                           key);
out:
    return ret;
#else
    return 0;
#endif /* HAVE_LIB_XML */
}

int
cli_xml_output_vol_getopts(dict_t *dict, int op_ret, int op_errno,
                           char *op_errstr)
{
#if (HAVE_LIB_XML)
    int i = 0;
    int ret = -1;
    int count = 0;
    xmlTextWriterPtr writer = NULL;
    xmlDocPtr doc = NULL;
    char *key = NULL;
    char *value = NULL;
    char dict_key[50] = {
        0,
    };

    ret = cli_begin_xml_output(&writer, &doc);
    if (ret)
        goto out;

    ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
    if (ret)
        goto out;

    ret = xmlTextWriterStartElement(writer, (xmlChar *)"volGetopts");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = dict_get_int32(dict, "count", &count);
    if (ret) {
        gf_log("cli", GF_LOG_ERROR,
               "Failed to retrieve count "
               "from the dictionary");
        goto out;
    }
    if (count <= 0) {
        gf_log("cli", GF_LOG_ERROR,
               "Value of count :%d is "
               "invalid",
               count);
        ret = -1;
        goto out;
    }
    ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
                                          count);

    XML_RET_CHECK_AND_GOTO(ret, out);

    for (i = 1; i <= count; i++) {
        sprintf(dict_key, "key%d", i);
        ret = dict_get_str(dict, dict_key, &key);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR,
                   "Failed to"
                   " retrieve %s from the "
                   "dictionary",
                   dict_key);
            goto out;
        }
        sprintf(dict_key, "value%d", i);
        ret = dict_get_str(dict, dict_key, &value);
        if (ret) {
            gf_log("cli", GF_LOG_ERROR,
                   "Failed to "
                   "retrieve key value for %s from"
                   "the dictionary",
                   dict_key);
            goto out;
        }
        ret = xmlTextWriterStartElement(writer, (xmlChar *)"Opt");
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"Option", "%s",
                                              key);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"Value", "%s",
                                              value);
        XML_RET_CHECK_AND_GOTO(ret, out);

        ret = xmlTextWriterEndElement(writer);
        XML_RET_CHECK_AND_GOTO(ret, out);
    }
    ret = cli_end_xml_output(writer, doc);

out:
    gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
    return ret;
#else
    return 0;
#endif /* HAVE_LIB_XML */
}

int
cli_quota_list_xml_error(cli_local_t *local, char *path, char *errstr)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"limit");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"path",
                                          "%s", path);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"errstr",
                                          "%s", errstr);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    return ret;
#else
    return 0;
#endif
}

int
cli_quota_xml_output(cli_local_t *local, char *path, int64_t hl_str,
                     char *sl_final, int64_t sl_num, int64_t used,
                     int64_t avail, char *sl, char *hl, gf_boolean_t limit_set)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"limit");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"path",
                                          "%s", path);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"hard_limit", !limit_set ? "N/A" : "%" PRId64,
        hl_str);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer,
                                          (xmlChar *)"soft_limit_percent",
                                          !limit_set ? "N/A" : "%s", sl_final);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"soft_limit_value",
        !limit_set ? "N/A" : "%" PRId64, sl_num);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"used_space", "%" PRId64, used);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"avail_space",
        !limit_set ? "N/A" : "%" PRId64, avail);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"sl_exceeded", !limit_set ? "N/A" : "%s", sl);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"hl_exceeded", !limit_set ? "N/A" : "%s", hl);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    return ret;
#else
    return 0;
#endif /* HAVE_LIB_XML */
}

int
cli_quota_object_xml_output(cli_local_t *local, char *path, char *sl_str,
                            int64_t sl_val, quota_limits_t *limits,
                            quota_meta_t *used_space, int64_t avail, char *sl,
                            char *hl, gf_boolean_t limit_set)
{
#if (HAVE_LIB_XML)
    int ret = -1;

    ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"limit");
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"path",
                                          "%s", path);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"hard_limit", !limit_set ? "N/A" : "%" PRId64,
        limits->hl);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer,
                                          (xmlChar *)"soft_limit_percent",
                                          !limit_set ? "N/A" : "%s", sl_str);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"soft_limit_value",
        !limit_set ? "N/A" : "%" PRIu64, sl_val);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer,
                                          (xmlChar *)"file_count", "%" PRId64,
                                          used_space->file_count);

    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"dir_count",
                                          "%" PRIu64, used_space->dir_count);

    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"available",
                                          !limit_set ? "N/A" : "%" PRId64,
                                          avail);

    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"sl_exceeded", !limit_set ? "N/A" : "%s", sl);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterWriteFormatElement(
        local->writer, (xmlChar *)"hl_exceeded", !limit_set ? "N/A" : "%s", hl);
    XML_RET_CHECK_AND_GOTO(ret, out);

    ret = xmlTextWriterEndElement(local->writer);
    XML_RET_CHECK_AND_GOTO(ret, out);

out:
    return ret;
#else
    return 0;
#endif /* HAVE_LIB_XML */
}
