<commit_before>/*
 * virsh-domain-monitor.c: Commands to monitor domain status
 *
 * Copyright (C) 2005, 2007-2014 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 *  <NAME> <<EMAIL>>
 *  <NAME> <<EMAIL>>
 *  <NAME> <<EMAIL>>
 *
 */

#include <config.h>
#include "virsh-domain-monitor.h"

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xmlsave.h>

#include "internal.h"
#include "conf/domain_conf.h"
#include "intprops.h"
#include "viralloc.h"
#include "virmacaddr.h"
#include "virsh-domain.h"
#include "virxml.h"
#include "virstring.h"

VIR_ENUM_DECL(vshDomainIOError)
VIR_ENUM_IMPL(vshDomainIOError,
              VIR_DOMAIN_DISK_ERROR_LAST,
              N_("no error"),
              N_("unspecified error"),
              N_("no space"))

static const char *
vshDomainIOErrorToString(int error)
{
    const char *str = vshDomainIOErrorTypeToString(error);
    return str ? _(str) : _("unknown error");
}

/* extract description or title from domain xml */
char *
vshGetDomainDescription(vshControl *ctl, virDomainPtr dom, bool title,
                        unsigned int flags)
{
    char *desc = NULL;
    char *domxml = NULL;
    virErrorPtr err = NULL;
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    int type;

    if (title)
        type = VIR_DOMAIN_METADATA_TITLE;
    else
        type = VIR_DOMAIN_METADATA_DESCRIPTION;

    if ((desc = virDomainGetMetadata(dom, type, NULL, flags))) {
        return desc;
    } else {
        err = virGetLastError();

        if (err && err->code == VIR_ERR_NO_DOMAIN_METADATA) {
            desc = vshStrdup(ctl, "");
            vshResetLibvirtError();
            return desc;
        }

        if (err && err->code != VIR_ERR_NO_SUPPORT)
            return desc;
    }

    /* fall back to xml */
    /* get domain's xml description and extract the title/description */
    if (!(domxml = virDomainGetXMLDesc(dom, flags))) {
        vshError(ctl, "%s", _("Failed to retrieve domain XML"));
        goto cleanup;
    }
    doc = virXMLParseStringCtxt(domxml, _("(domain_definition)"), &ctxt);
    if (!doc) {
        vshError(ctl, "%s", _("Couldn't parse domain XML"));
        goto cleanup;
    }
    if (title)
        desc = virXPathString("string(./title[1])", ctxt);
    else
        desc = virXPathString("string(./description[1])", ctxt);

    if (!desc)
        desc = vshStrdup(ctl, "");

 cleanup:
    VIR_FREE(domxml);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);

    return desc;
}

VIR_ENUM_DECL(vshDomainControlState)
VIR_ENUM_IMPL(vshDomainControlState,
              VIR_DOMAIN_CONTROL_LAST,
              N_("ok"),
              N_("background job"),
              N_("occupied"),
              N_("error"))

static const char *
vshDomainControlStateToString(int state)
{
    const char *str = vshDomainControlStateTypeToString(state);
    return str ? _(str) : _("unknown");
}

VIR_ENUM_DECL(vshDomainState)
VIR_ENUM_IMPL(vshDomainState,
              VIR_DOMAIN_LAST,
              N_("no state"),
              N_("running"),
              N_("idle"),
              N_("paused"),
              N_("in shutdown"),
              N_("shut off"),
              N_("crashed"),
              N_("pmsuspended"))

static const char *
vshDomainStateToString(int state)
{
    const char *str = vshDomainStateTypeToString(state);
    return str ? _(str) : _("no state");
}

VIR_ENUM_DECL(vshDomainNostateReason)
VIR_ENUM_IMPL(vshDomainNostateReason,
              VIR_DOMAIN_NOSTATE_LAST,
              N_("unknown"))

VIR_ENUM_DECL(vshDomainRunningReason)
VIR_ENUM_IMPL(vshDomainRunningReason,
              VIR_DOMAIN_RUNNING_LAST,
              N_("unknown"),
              N_("booted"),
              N_("migrated"),
              N_("restored"),
              N_("from snapshot"),
              N_("unpaused"),
              N_("migration canceled"),
              N_("save canceled"),
              N_("event wakeup"),
              N_("crashed"))

VIR_ENUM_DECL(vshDomainBlockedReason)
VIR_ENUM_IMPL(vshDomainBlockedReason,
              VIR_DOMAIN_BLOCKED_LAST,
              N_("unknown"))

VIR_ENUM_DECL(vshDomainPausedReason)
VIR_ENUM_IMPL(vshDomainPausedReason,
              VIR_DOMAIN_PAUSED_LAST,
              N_("unknown"),
              N_("user"),
              N_("migrating"),
              N_("saving"),
              N_("dumping"),
              N_("I/O error"),
              N_("watchdog"),
              N_("from snapshot"),
              N_("shutting down"),
              N_("creating snapshot"),
              N_("crashed"))

VIR_ENUM_DECL(vshDomainShutdownReason)
VIR_ENUM_IMPL(vshDomainShutdownReason,
              VIR_DOMAIN_SHUTDOWN_LAST,
              N_("unknown"),
              N_("user"))

VIR_ENUM_DECL(vshDomainShutoffReason)
VIR_ENUM_IMPL(vshDomainShutoffReason,
              VIR_DOMAIN_SHUTOFF_LAST,
              N_("unknown"),
              N_("shutdown"),
              N_("destroyed"),
              N_("crashed"),
              N_("migrated"),
              N_("saved"),
              N_("failed"),
              N_("from snapshot"))

VIR_ENUM_DECL(vshDomainCrashedReason)
VIR_ENUM_IMPL(vshDomainCrashedReason,
              VIR_DOMAIN_CRASHED_LAST,
              N_("unknown"),
              N_("panicked"))

VIR_ENUM_DECL(vshDomainPMSuspendedReason)
VIR_ENUM_IMPL(vshDomainPMSuspendedReason,
              VIR_DOMAIN_PMSUSPENDED_LAST,
              N_("unknown"))

static const char *
vshDomainStateReasonToString(int state, int reason)
{
    const char *str = NULL;
    switch ((virDomainState) state) {
    case VIR_DOMAIN_NOSTATE:
        str = vshDomainNostateReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_RUNNING:
        str = vshDomainRunningReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_BLOCKED:
        str = vshDomainBlockedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_PAUSED:
        str = vshDomainPausedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_SHUTDOWN:
        str = vshDomainShutdownReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_SHUTOFF:
        str = vshDomainShutoffReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_CRASHED:
        str = vshDomainCrashedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_PMSUSPENDED:
        str = vshDomainPMSuspendedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_LAST:
        ;
    }

    return str ? _(str) : _("unknown");
}

/*
 * "dommemstat" command
 */
static const vshCmdInfo info_dommemstat[] = {
    {.name = "help",
     .data = N_("get memory statistics for a domain")
    },
    {.name = "desc",
     .data = N_("Get memory statistics for a running domain.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_dommemstat[] = {
    {.name = "domain",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("domain name, id or uuid")
    },
    {.name = "period",
     .type = VSH_OT_STRING,
     .flags = VSH_OFLAG_REQ_OPT,
     .help = N_("period in seconds to set collection")
    },
    {.name = "config",
     .type = VSH_OT_BOOL,
     .help = N_("affect next boot")
    },
    {.name = "live",
     .type = VSH_OT_BOOL,
     .help = N_("affect running domain")
    },
    {.name = "current",
     .type = VSH_OT_BOOL,
     .help = N_("affect current domain")
    },
    {.name = NULL}
};

static bool
cmdDomMemStat(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
    const char *name;
    virDomainMemoryStatStruct stats[VIR_DOMAIN_MEMORY_STAT_NR];
    unsigned int nr_stats;
    size_t i;
    bool ret = false;
    int rv = 0;
    int period = -1;
    bool config = vshCommandOptBool(cmd, "config");
    bool live = vshCommandOptBool(cmd, "live");
    bool current = vshCommandOptBool(cmd, "current");
    unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;

    VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
    VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
    if (config)
        flags |= VIR_DOMAIN_AFFECT_CONFIG;
    if (live)
        flags |= VIR_DOMAIN_AFFECT_LIVE;

    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
        return false;

    /* If none of the options were specified and we're active
     * then be sure to allow active modification */
    if (!current && !live && !config && virDomainIsActive(dom) == 1)
        flags |= VIR_DOMAIN_AFFECT_LIVE;

    /* Providing a period will adjust the balloon driver collection period.
     * This is not really an unsigned long, but it
     */
    if ((rv = vshCommandOptInt(cmd, "period", &period)) < 0) {
        vshError(ctl, "%s",
                 _("Unable to parse integer parameter."));
        goto cleanup;
    }
    if (rv > 0) {
        if (period < 0) {
            vshError(ctl, _("Invalid collection period value '%d'"), period);
            goto cleanup;
        }

        if (virDomainSetMemoryStatsPeriod(dom, period, flags) < 0) {
            vshError(ctl, "%s",
                     _("Unable to change balloon collection period."));
        } else {
            ret = true;
        }
        goto cleanup;
    }

    nr_stats = virDomainMemoryStats(dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0);
    if (nr_stats == -1) {
        vshError(ctl, _("Failed to get memory statistics for domain %s"), name);
        goto cleanup;
    }

    for (i = 0; i < nr_stats; i++) {
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
            vshPrint(ctl, "swap_in %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
            vshPrint(ctl, "swap_out %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
            vshPrint(ctl, "major_fault %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
            vshPrint(ctl, "minor_fault %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED)
            vshPrint(ctl, "unused %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE)
            vshPrint(ctl, "available %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON)
            vshPrint(ctl, "actual %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS)
            vshPrint(ctl, "rss %llu\n", stats[i].val);
    }

    ret = true;
 cleanup:
    virDomainFree(dom);
    return ret;
}

/*
 * "domblkinfo" command
 */
static const vshCmdInfo info_domblkinfo[] = {
    {.name = "help",
     .data = N_("domain block device size information")
    },
    {.name = "desc",
     .data = N_("Get block device size info for a domain.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_domblkinfo[] = {
    {.name = "domain",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("domain name, id or uuid")
    },
    {.name = "device",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("block device")
    },
    {.name = NULL}
};

static bool
cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd)
{
    virDomainBlockInfo info;
    virDomainPtr dom;
    bool ret = false;
    const char *device = NULL;

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
        return false;

    if (vshCommandOptStringReq(ctl, cmd, "device", &device) < 0)
        goto cleanup;

    if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
        goto cleanup;

    vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity);
    vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation);
    vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical);

    ret = true;

 cleanup:
    virDomainFree(dom);
    return ret;
}

/*
 * "domblklist" command
 */
static const vshCmdInfo info_domblklist[] = {
    {.name = "help",
     .data = N_("list all domain blocks")
    },
    {.name = "desc",
     .data = N_("Get the summary of block devices for a domain.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_domblklist[] = {
    {.name = "domain",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("domain name, id or uuid")
    },
    {.name = "inactive",
     .type = VSH_OT_BOOL,
     .help = N_("get inactive rather than running configuration")
    },
    {.name = "details",
     .type = VSH_OT_BOOL,
     .help = N_("additionally display the type and device value")
    },
    {.name = NULL}
};

static bool
cmdDomblklist(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
    bool ret = false;
    unsigned int flags = 0;
    char *xml = NULL;
    xmlDocPtr xmldoc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    int ndisks;
    xmlNodePtr *disks = NULL;
    size_t i;
    bool details = false;

    if (vshCommandOptBool(cmd, "inactive"))
        flags |= VIR_DOMAIN_XML_INACTIVE;

    details = vshCommandOptBool(cmd, "details");

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
        return false;

    xml = virDomainGetXMLDesc(dom, flags);
    if (!xml)
        goto cleanup;

    xmldoc = virXMLParseStringCtxt(xml, _("(domain_definition)"), &ctxt);
    if (!xmldoc)
        goto cleanup;

    ndisks = virXPathNodeSet("./devices/disk", ctxt, &disks);
    if (ndisks < 0)
        goto cleanup;

    if (details)
        vshPrintExtra(ctl, "%-10s %-10s %-10s %s\n", _("Type"),
                      _("Device"), _("Target"), _("Source"));
    else
        vshPrintExtra(ctl, "%-10s %s\n", _("Target"), _("Source"));

    vshPrintExtra(ctl, "------------------------------------------------\n");

    for (i = 0; i < ndisks; i++) {
        char *type = NULL;
        char *device = NULL;
        char *target;
        char *source;

        ctxt->node = disks[i];

        if (details) {
            type = virXPathString("string(./@type)", ctxt);
            device = virXPathString("string(./@device)", ctxt);
            if (!type || !device) {
                vshPrint(ctl, "unable to query block list details");
                VIR_FREE(type);
                VIR_FREE(device);
                goto cleanup;
            }
        }

        target = virXPathString("string(./target/@dev)", ctxt);
        if (!target) {
            vshError(ctl, "unable to query block list");
            VIR_FREE(type);
            VIR_FREE(device);
            goto cleanup;
        }
        source = virXPathString("string(./source/@file"
                                "|./source/@dev"
                                "|./source/@dir"
                                "|./source/@name)", ctxt);
        if (details) {
            vshPrint(ctl, "%-10s %-10s %-10s %s\n", type, device,
                     target, source ? source : "-");
            VIR_FREE(type);
            VIR_FREE(device);
        } else {
            vshPrint(ctl, "%-10s %s\n", target, source ? source : "-");
        }

        VIR_FREE(target);
        VIR_FREE(source);
    }

    ret = true;

 cleanup:
    VIR_FREE(disks);
    virDomainFree(dom);
    VIR_FREE(xml);
    xmlFreeDoc(xmldoc);
    xmlXPathFreeContext(ctxt);
    return ret;
}

/*
 * "domiflist" command
 */
static const vshCmdInfo info_domiflist[] = {
    {"help", N_("list all domain virtual interfaces")},<commit_msg>virsh: Adjust domblklist to understand disk volume syntax<commit_after>/*
 * virsh-domain-monitor.c: Commands to monitor domain status
 *
 * Copyright (C) 2005, 2007-2014 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 *  <NAME> <<EMAIL>>
 *  <NAME> <<EMAIL>>
 *  <NAME> <<EMAIL>>
 *
 */

#include <config.h>
#include "virsh-domain-monitor.h"

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xmlsave.h>

#include "internal.h"
#include "conf/domain_conf.h"
#include "intprops.h"
#include "viralloc.h"
#include "virmacaddr.h"
#include "virsh-domain.h"
#include "virxml.h"
#include "virstring.h"

VIR_ENUM_DECL(vshDomainIOError)
VIR_ENUM_IMPL(vshDomainIOError,
              VIR_DOMAIN_DISK_ERROR_LAST,
              N_("no error"),
              N_("unspecified error"),
              N_("no space"))

static const char *
vshDomainIOErrorToString(int error)
{
    const char *str = vshDomainIOErrorTypeToString(error);
    return str ? _(str) : _("unknown error");
}

/* extract description or title from domain xml */
char *
vshGetDomainDescription(vshControl *ctl, virDomainPtr dom, bool title,
                        unsigned int flags)
{
    char *desc = NULL;
    char *domxml = NULL;
    virErrorPtr err = NULL;
    xmlDocPtr doc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    int type;

    if (title)
        type = VIR_DOMAIN_METADATA_TITLE;
    else
        type = VIR_DOMAIN_METADATA_DESCRIPTION;

    if ((desc = virDomainGetMetadata(dom, type, NULL, flags))) {
        return desc;
    } else {
        err = virGetLastError();

        if (err && err->code == VIR_ERR_NO_DOMAIN_METADATA) {
            desc = vshStrdup(ctl, "");
            vshResetLibvirtError();
            return desc;
        }

        if (err && err->code != VIR_ERR_NO_SUPPORT)
            return desc;
    }

    /* fall back to xml */
    /* get domain's xml description and extract the title/description */
    if (!(domxml = virDomainGetXMLDesc(dom, flags))) {
        vshError(ctl, "%s", _("Failed to retrieve domain XML"));
        goto cleanup;
    }
    doc = virXMLParseStringCtxt(domxml, _("(domain_definition)"), &ctxt);
    if (!doc) {
        vshError(ctl, "%s", _("Couldn't parse domain XML"));
        goto cleanup;
    }
    if (title)
        desc = virXPathString("string(./title[1])", ctxt);
    else
        desc = virXPathString("string(./description[1])", ctxt);

    if (!desc)
        desc = vshStrdup(ctl, "");

 cleanup:
    VIR_FREE(domxml);
    xmlXPathFreeContext(ctxt);
    xmlFreeDoc(doc);

    return desc;
}

VIR_ENUM_DECL(vshDomainControlState)
VIR_ENUM_IMPL(vshDomainControlState,
              VIR_DOMAIN_CONTROL_LAST,
              N_("ok"),
              N_("background job"),
              N_("occupied"),
              N_("error"))

static const char *
vshDomainControlStateToString(int state)
{
    const char *str = vshDomainControlStateTypeToString(state);
    return str ? _(str) : _("unknown");
}

VIR_ENUM_DECL(vshDomainState)
VIR_ENUM_IMPL(vshDomainState,
              VIR_DOMAIN_LAST,
              N_("no state"),
              N_("running"),
              N_("idle"),
              N_("paused"),
              N_("in shutdown"),
              N_("shut off"),
              N_("crashed"),
              N_("pmsuspended"))

static const char *
vshDomainStateToString(int state)
{
    const char *str = vshDomainStateTypeToString(state);
    return str ? _(str) : _("no state");
}

VIR_ENUM_DECL(vshDomainNostateReason)
VIR_ENUM_IMPL(vshDomainNostateReason,
              VIR_DOMAIN_NOSTATE_LAST,
              N_("unknown"))

VIR_ENUM_DECL(vshDomainRunningReason)
VIR_ENUM_IMPL(vshDomainRunningReason,
              VIR_DOMAIN_RUNNING_LAST,
              N_("unknown"),
              N_("booted"),
              N_("migrated"),
              N_("restored"),
              N_("from snapshot"),
              N_("unpaused"),
              N_("migration canceled"),
              N_("save canceled"),
              N_("event wakeup"),
              N_("crashed"))

VIR_ENUM_DECL(vshDomainBlockedReason)
VIR_ENUM_IMPL(vshDomainBlockedReason,
              VIR_DOMAIN_BLOCKED_LAST,
              N_("unknown"))

VIR_ENUM_DECL(vshDomainPausedReason)
VIR_ENUM_IMPL(vshDomainPausedReason,
              VIR_DOMAIN_PAUSED_LAST,
              N_("unknown"),
              N_("user"),
              N_("migrating"),
              N_("saving"),
              N_("dumping"),
              N_("I/O error"),
              N_("watchdog"),
              N_("from snapshot"),
              N_("shutting down"),
              N_("creating snapshot"),
              N_("crashed"))

VIR_ENUM_DECL(vshDomainShutdownReason)
VIR_ENUM_IMPL(vshDomainShutdownReason,
              VIR_DOMAIN_SHUTDOWN_LAST,
              N_("unknown"),
              N_("user"))

VIR_ENUM_DECL(vshDomainShutoffReason)
VIR_ENUM_IMPL(vshDomainShutoffReason,
              VIR_DOMAIN_SHUTOFF_LAST,
              N_("unknown"),
              N_("shutdown"),
              N_("destroyed"),
              N_("crashed"),
              N_("migrated"),
              N_("saved"),
              N_("failed"),
              N_("from snapshot"))

VIR_ENUM_DECL(vshDomainCrashedReason)
VIR_ENUM_IMPL(vshDomainCrashedReason,
              VIR_DOMAIN_CRASHED_LAST,
              N_("unknown"),
              N_("panicked"))

VIR_ENUM_DECL(vshDomainPMSuspendedReason)
VIR_ENUM_IMPL(vshDomainPMSuspendedReason,
              VIR_DOMAIN_PMSUSPENDED_LAST,
              N_("unknown"))

static const char *
vshDomainStateReasonToString(int state, int reason)
{
    const char *str = NULL;
    switch ((virDomainState) state) {
    case VIR_DOMAIN_NOSTATE:
        str = vshDomainNostateReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_RUNNING:
        str = vshDomainRunningReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_BLOCKED:
        str = vshDomainBlockedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_PAUSED:
        str = vshDomainPausedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_SHUTDOWN:
        str = vshDomainShutdownReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_SHUTOFF:
        str = vshDomainShutoffReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_CRASHED:
        str = vshDomainCrashedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_PMSUSPENDED:
        str = vshDomainPMSuspendedReasonTypeToString(reason);
        break;
    case VIR_DOMAIN_LAST:
        ;
    }

    return str ? _(str) : _("unknown");
}

/*
 * "dommemstat" command
 */
static const vshCmdInfo info_dommemstat[] = {
    {.name = "help",
     .data = N_("get memory statistics for a domain")
    },
    {.name = "desc",
     .data = N_("Get memory statistics for a running domain.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_dommemstat[] = {
    {.name = "domain",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("domain name, id or uuid")
    },
    {.name = "period",
     .type = VSH_OT_STRING,
     .flags = VSH_OFLAG_REQ_OPT,
     .help = N_("period in seconds to set collection")
    },
    {.name = "config",
     .type = VSH_OT_BOOL,
     .help = N_("affect next boot")
    },
    {.name = "live",
     .type = VSH_OT_BOOL,
     .help = N_("affect running domain")
    },
    {.name = "current",
     .type = VSH_OT_BOOL,
     .help = N_("affect current domain")
    },
    {.name = NULL}
};

static bool
cmdDomMemStat(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
    const char *name;
    virDomainMemoryStatStruct stats[VIR_DOMAIN_MEMORY_STAT_NR];
    unsigned int nr_stats;
    size_t i;
    bool ret = false;
    int rv = 0;
    int period = -1;
    bool config = vshCommandOptBool(cmd, "config");
    bool live = vshCommandOptBool(cmd, "live");
    bool current = vshCommandOptBool(cmd, "current");
    unsigned int flags = VIR_DOMAIN_AFFECT_CURRENT;

    VSH_EXCLUSIVE_OPTIONS_VAR(current, live);
    VSH_EXCLUSIVE_OPTIONS_VAR(current, config);
    if (config)
        flags |= VIR_DOMAIN_AFFECT_CONFIG;
    if (live)
        flags |= VIR_DOMAIN_AFFECT_LIVE;

    if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
        return false;

    /* If none of the options were specified and we're active
     * then be sure to allow active modification */
    if (!current && !live && !config && virDomainIsActive(dom) == 1)
        flags |= VIR_DOMAIN_AFFECT_LIVE;

    /* Providing a period will adjust the balloon driver collection period.
     * This is not really an unsigned long, but it
     */
    if ((rv = vshCommandOptInt(cmd, "period", &period)) < 0) {
        vshError(ctl, "%s",
                 _("Unable to parse integer parameter."));
        goto cleanup;
    }
    if (rv > 0) {
        if (period < 0) {
            vshError(ctl, _("Invalid collection period value '%d'"), period);
            goto cleanup;
        }

        if (virDomainSetMemoryStatsPeriod(dom, period, flags) < 0) {
            vshError(ctl, "%s",
                     _("Unable to change balloon collection period."));
        } else {
            ret = true;
        }
        goto cleanup;
    }

    nr_stats = virDomainMemoryStats(dom, stats, VIR_DOMAIN_MEMORY_STAT_NR, 0);
    if (nr_stats == -1) {
        vshError(ctl, _("Failed to get memory statistics for domain %s"), name);
        goto cleanup;
    }

    for (i = 0; i < nr_stats; i++) {
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_IN)
            vshPrint(ctl, "swap_in %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_SWAP_OUT)
            vshPrint(ctl, "swap_out %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MAJOR_FAULT)
            vshPrint(ctl, "major_fault %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_MINOR_FAULT)
            vshPrint(ctl, "minor_fault %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_UNUSED)
            vshPrint(ctl, "unused %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_AVAILABLE)
            vshPrint(ctl, "available %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON)
            vshPrint(ctl, "actual %llu\n", stats[i].val);
        if (stats[i].tag == VIR_DOMAIN_MEMORY_STAT_RSS)
            vshPrint(ctl, "rss %llu\n", stats[i].val);
    }

    ret = true;
 cleanup:
    virDomainFree(dom);
    return ret;
}

/*
 * "domblkinfo" command
 */
static const vshCmdInfo info_domblkinfo[] = {
    {.name = "help",
     .data = N_("domain block device size information")
    },
    {.name = "desc",
     .data = N_("Get block device size info for a domain.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_domblkinfo[] = {
    {.name = "domain",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("domain name, id or uuid")
    },
    {.name = "device",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("block device")
    },
    {.name = NULL}
};

static bool
cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd)
{
    virDomainBlockInfo info;
    virDomainPtr dom;
    bool ret = false;
    const char *device = NULL;

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
        return false;

    if (vshCommandOptStringReq(ctl, cmd, "device", &device) < 0)
        goto cleanup;

    if (virDomainGetBlockInfo(dom, device, &info, 0) < 0)
        goto cleanup;

    vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity);
    vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation);
    vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical);

    ret = true;

 cleanup:
    virDomainFree(dom);
    return ret;
}

/*
 * "domblklist" command
 */
static const vshCmdInfo info_domblklist[] = {
    {.name = "help",
     .data = N_("list all domain blocks")
    },
    {.name = "desc",
     .data = N_("Get the summary of block devices for a domain.")
    },
    {.name = NULL}
};

static const vshCmdOptDef opts_domblklist[] = {
    {.name = "domain",
     .type = VSH_OT_DATA,
     .flags = VSH_OFLAG_REQ,
     .help = N_("domain name, id or uuid")
    },
    {.name = "inactive",
     .type = VSH_OT_BOOL,
     .help = N_("get inactive rather than running configuration")
    },
    {.name = "details",
     .type = VSH_OT_BOOL,
     .help = N_("additionally display the type and device value")
    },
    {.name = NULL}
};

static bool
cmdDomblklist(vshControl *ctl, const vshCmd *cmd)
{
    virDomainPtr dom;
    bool ret = false;
    unsigned int flags = 0;
    char *xml = NULL;
    xmlDocPtr xmldoc = NULL;
    xmlXPathContextPtr ctxt = NULL;
    int ndisks;
    xmlNodePtr *disks = NULL;
    size_t i;
    bool details = false;

    if (vshCommandOptBool(cmd, "inactive"))
        flags |= VIR_DOMAIN_XML_INACTIVE;

    details = vshCommandOptBool(cmd, "details");

    if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
        return false;

    xml = virDomainGetXMLDesc(dom, flags);
    if (!xml)
        goto cleanup;

    xmldoc = virXMLParseStringCtxt(xml, _("(domain_definition)"), &ctxt);
    if (!xmldoc)
        goto cleanup;

    ndisks = virXPathNodeSet("./devices/disk", ctxt, &disks);
    if (ndisks < 0)
        goto cleanup;

    if (details)
        vshPrintExtra(ctl, "%-10s %-10s %-10s %s\n", _("Type"),
                      _("Device"), _("Target"), _("Source"));
    else
        vshPrintExtra(ctl, "%-10s %s\n", _("Target"), _("Source"));

    vshPrintExtra(ctl, "------------------------------------------------\n");

    for (i = 0; i < ndisks; i++) {
        char *type = NULL;
        char *device = NULL;
        char *target;
        char *source;

        ctxt->node = disks[i];

        if (details) {
            type = virXPathString("string(./@type)", ctxt);
            device = virXPathString("string(./@device)", ctxt);
            if (!type || !device) {
                vshPrint(ctl, "unable to query block list details");
                VIR_FREE(type);
                VIR_FREE(device);
                goto cleanup;
            }
        }

        target = virXPathString("string(./target/@dev)", ctxt);
        if (!target) {
            vshError(ctl, "unable to query block list");
            VIR_FREE(type);
            VIR_FREE(device);
            goto cleanup;
        }
        source = virXPathString("string(./source/@file"
                                "|./source/@dev"
                                "|./source/@dir"
                                "|./source/@name"
                                "|./source/@volume)", ctxt);
        if (details) {
            vshPrint(ctl, "%-10s %-10s %-10s %s\n", type, device,
                     target, source ? source : "-");
            VIR_FREE(type);
            VIR_FREE(device);
        } else {
            vshPrint(ctl, "%-10s %s\n", target, source ? source : "-");
        }

        VIR_FREE(target);
        VIR_FREE(source);
    }

    ret = true;

 cleanup:
    VIR_FREE(disks);
    virDomainFree(dom);
    VIR_FREE(xml);
    xmlFreeDoc(xmldoc);
    xmlXPathFreeContext(ctxt);
    return ret;
}

/*
 * "domiflist" command
 */
static const vshCmdInfo info_domiflist[] = {
    {"help", N_("list all domain virtual interfaces")},
{'fraction_non_alphanumeric': 0.13067573524781156, 'fraction_numerical': 0.0034007179293406384, 'mean_word_length': 2.325549738219895, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 62}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6860652', 'n_tokens_mistral': 10725, 'n_tokens_neox': 10492, 'n_words': 2375}