This splits commands commands to monitor domain status into virsh-domain-monitor.c. The helpers not for common use are moved too. Standard copyright is added. * tools/virsh.c: Remove commands for domain monitoring group and a few helpers ( vshDomainIOErrorToString, vshGetDomainDescription, vshDomainControlStateToString, vshDomainStateToString) not for common use. * tools/virsh-domain-monitor.c: New file, filled with commands of domain monitor group. --- tools/virsh-domain-monitor.c | 1685 +++++++++++++++++++++++++++++++++++++ tools/virsh.c | 1904 +++--------------------------------------- 2 files changed, 1807 insertions(+), 1782 deletions(-) create mode 100644 tools/virsh-domain-monitor.c diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c new file mode 100644 index 0000000..1a61f62 --- /dev/null +++ b/tools/virsh-domain-monitor.c @@ -0,0 +1,1685 @@ +/* + * virsh-domain.c: Commands to monitor domain status + * + * Copyright (C) 2005, 2007-2012 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/>. + * + * Daniel Veillard <veillard@xxxxxxxxxx> + * Karel Zak <kzak@xxxxxxxxxx> + * Daniel P. Berrange <berrange@xxxxxxxxxx> + * + */ + +static const char * +vshDomainIOErrorToString(int error) +{ + switch ((virDomainDiskErrorCode) error) { + case VIR_DOMAIN_DISK_ERROR_NONE: + return _("no error"); + case VIR_DOMAIN_DISK_ERROR_UNSPEC: + return _("unspecified error"); + case VIR_DOMAIN_DISK_ERROR_NO_SPACE: + return _("no space"); + case VIR_DOMAIN_DISK_ERROR_LAST: + ; + } + + return _("unknown error"); +} + +/* extract description or title from domain xml */ +static 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, ""); + virResetLastError(); + 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; +} +static const char * +vshDomainControlStateToString(int state) +{ + switch ((virDomainControlState) state) { + case VIR_DOMAIN_CONTROL_OK: + return N_("ok"); + case VIR_DOMAIN_CONTROL_JOB: + return N_("background job"); + case VIR_DOMAIN_CONTROL_OCCUPIED: + return N_("occupied"); + case VIR_DOMAIN_CONTROL_ERROR: + return N_("error"); + default: + ; + } + + return N_("unknown"); +} + +static const char * +vshDomainStateToString(int state) +{ + /* Can't use virDomainStateTypeToString, because we want to mark + * * strings for translation. */ + switch ((virDomainState) state) { + case VIR_DOMAIN_RUNNING: + return N_("running"); + case VIR_DOMAIN_BLOCKED: + return N_("idle"); + case VIR_DOMAIN_PAUSED: + return N_("paused"); + case VIR_DOMAIN_SHUTDOWN: + return N_("in shutdown"); + case VIR_DOMAIN_SHUTOFF: + return N_("shut off"); + case VIR_DOMAIN_CRASHED: + return N_("crashed"); + case VIR_DOMAIN_PMSUSPENDED: + return N_("pmsuspended"); + case VIR_DOMAIN_NOSTATE: + default: + ;/*FALLTHROUGH*/ + } + return N_("no state"); /* = dom0 state */ +} + +static const char * +vshDomainStateReasonToString(int state, int reason) +{ + switch ((virDomainState) state) { + case VIR_DOMAIN_NOSTATE: + switch ((virDomainNostateReason) reason) { + case VIR_DOMAIN_NOSTATE_UNKNOWN: + case VIR_DOMAIN_NOSTATE_LAST: + ; + } + break; + + case VIR_DOMAIN_RUNNING: + switch ((virDomainRunningReason) reason) { + case VIR_DOMAIN_RUNNING_BOOTED: + return N_("booted"); + case VIR_DOMAIN_RUNNING_MIGRATED: + return N_("migrated"); + case VIR_DOMAIN_RUNNING_RESTORED: + return N_("restored"); + case VIR_DOMAIN_RUNNING_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_RUNNING_UNPAUSED: + return N_("unpaused"); + case VIR_DOMAIN_RUNNING_MIGRATION_CANCELED: + return N_("migration canceled"); + case VIR_DOMAIN_RUNNING_SAVE_CANCELED: + return N_("save canceled"); + case VIR_DOMAIN_RUNNING_WAKEUP: + return N_("event wakeup"); + case VIR_DOMAIN_RUNNING_UNKNOWN: + case VIR_DOMAIN_RUNNING_LAST: + ; + } + break; + + case VIR_DOMAIN_BLOCKED: + switch ((virDomainBlockedReason) reason) { + case VIR_DOMAIN_BLOCKED_UNKNOWN: + case VIR_DOMAIN_BLOCKED_LAST: + ; + } + break; + + case VIR_DOMAIN_PAUSED: + switch ((virDomainPausedReason) reason) { + case VIR_DOMAIN_PAUSED_USER: + return N_("user"); + case VIR_DOMAIN_PAUSED_MIGRATION: + return N_("migrating"); + case VIR_DOMAIN_PAUSED_SAVE: + return N_("saving"); + case VIR_DOMAIN_PAUSED_DUMP: + return N_("dumping"); + case VIR_DOMAIN_PAUSED_IOERROR: + return N_("I/O error"); + case VIR_DOMAIN_PAUSED_WATCHDOG: + return N_("watchdog"); + case VIR_DOMAIN_PAUSED_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_PAUSED_SHUTTING_DOWN: + return N_("shutting down"); + case VIR_DOMAIN_PAUSED_UNKNOWN: + case VIR_DOMAIN_PAUSED_LAST: + ; + } + break; + + case VIR_DOMAIN_SHUTDOWN: + switch ((virDomainShutdownReason) reason) { + case VIR_DOMAIN_SHUTDOWN_USER: + return N_("user"); + case VIR_DOMAIN_SHUTDOWN_UNKNOWN: + case VIR_DOMAIN_SHUTDOWN_LAST: + ; + } + break; + + case VIR_DOMAIN_SHUTOFF: + switch ((virDomainShutoffReason) reason) { + case VIR_DOMAIN_SHUTOFF_SHUTDOWN: + return N_("shutdown"); + case VIR_DOMAIN_SHUTOFF_DESTROYED: + return N_("destroyed"); + case VIR_DOMAIN_SHUTOFF_CRASHED: + return N_("crashed"); + case VIR_DOMAIN_SHUTOFF_MIGRATED: + return N_("migrated"); + case VIR_DOMAIN_SHUTOFF_SAVED: + return N_("saved"); + case VIR_DOMAIN_SHUTOFF_FAILED: + return N_("failed"); + case VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT: + return N_("from snapshot"); + case VIR_DOMAIN_SHUTOFF_UNKNOWN: + case VIR_DOMAIN_SHUTOFF_LAST: + ; + } + break; + + case VIR_DOMAIN_CRASHED: + switch ((virDomainCrashedReason) reason) { + case VIR_DOMAIN_CRASHED_UNKNOWN: + case VIR_DOMAIN_CRASHED_LAST: + ; + } + break; + + case VIR_DOMAIN_PMSUSPENDED: + switch ((virDomainPMSuspendedReason) reason) { + case VIR_DOMAIN_PMSUSPENDED_UNKNOWN: + case VIR_DOMAIN_PMSUSPENDED_LAST: + ; + } + break; + + case VIR_DOMAIN_LAST: + ; + } + + return N_("unknown"); +} + +/* + * "dommemstats" command + */ +static const vshCmdInfo info_dommemstat[] = { + {"help", N_("get memory statistics for a domain")}, + {"desc", N_("Get memory statistics for a running domain.")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_dommemstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name; + struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR]; + unsigned int nr_stats, i; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + 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); + virDomainFree(dom); + return false; + } + + 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); + } + + virDomainFree(dom); + return true; +} + +/* + * "domblkinfo" command + */ +static const vshCmdInfo info_domblkinfo[] = { + {"help", N_("domain block device size information")}, + {"desc", N_("Get block device size info for a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domblkinfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainBlockInfo info; + virDomainPtr dom; + bool ret = true; + const char *device = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptString(cmd, "device", &device) <= 0) { + virDomainFree(dom); + return false; + } + + if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) { + virDomainFree(dom); + return false; + } + + vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity); + vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation); + vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical); + + virDomainFree(dom); + return ret; +} + +/* + * "domblklist" command + */ +static const vshCmdInfo info_domblklist[] = { + {"help", N_("list all domain blocks")}, + {"desc", N_("Get the summary of block devices for a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domblklist[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"inactive", VSH_OT_BOOL, 0, + N_("get inactive rather than running configuration")}, + {"details", VSH_OT_BOOL, 0, + N_("additionally display the type and device value")}, + {NULL, 0, 0, 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; + int i; + bool details = false; + + if (vshCommandOptBool(cmd, "inactive")) + flags |= VIR_DOMAIN_XML_INACTIVE; + + details = vshCommandOptBool(cmd, "details"); + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + 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) + vshPrint(ctl, "%-10s %-10s %-10s %s\n", _("Type"), + _("Device"), _("Target"), _("Source")); + else + vshPrint(ctl, "%-10s %s\n", _("Target"), _("Source")); + + vshPrint(ctl, "------------------------------------------------\n"); + + for (i = 0; i < ndisks; i++) { + char *type; + char *device; + char *target; + char *source; + + ctxt->node = disks[i]; + + if (details) { + type = virXPathString("string(./@type)", ctxt); + device = virXPathString("string(./@device)", ctxt); + } + + target = virXPathString("string(./target/@dev)", ctxt); + if (!target) { + vshError(ctl, "unable to query block list"); + 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")}, + {"desc", N_("Get the summary of virtual interfaces for a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domiflist[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"inactive", VSH_OT_BOOL, 0, + N_("get inactive rather than running configuration")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomiflist(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = false; + unsigned int flags = 0; + char *xml = NULL; + xmlDocPtr xmldoc = NULL; + xmlXPathContextPtr ctxt = NULL; + int ninterfaces; + xmlNodePtr *interfaces = NULL; + int i; + + if (vshCommandOptBool(cmd, "inactive")) + flags |= VIR_DOMAIN_XML_INACTIVE; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + 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; + + ninterfaces = virXPathNodeSet("./devices/interface", ctxt, &interfaces); + if (ninterfaces < 0) + goto cleanup; + + vshPrint(ctl, "%-10s %-10s %-10s %-11s %s\n", _("Interface"), _("Type"), + _("Source"), _("Model"), _("MAC")); + vshPrint(ctl, "-------------------------------------------------------\n"); + + for (i = 0; i < ninterfaces; i++) { + char *type = NULL; + char *source = NULL; + char *target = NULL; + char *model = NULL; + char *mac = NULL; + + ctxt->node = interfaces[i]; + type = virXPathString("string(./@type)", ctxt); + + source = virXPathString("string(./source/@bridge" + "|./source/@dev" + "|./source/@network" + "|./source/@name)", ctxt); + + target = virXPathString("string(./target/@dev)", ctxt); + model = virXPathString("string(./model/@type)", ctxt); + mac = virXPathString("string(./mac/@address)", ctxt); + + vshPrint(ctl, "%-10s %-10s %-10s %-11s %-10s\n", + target ? target : "-", + type, + source ? source : "-", + model ? model : "-", + mac ? mac : "-"); + + VIR_FREE(type); + VIR_FREE(source); + VIR_FREE(target); + VIR_FREE(model); + VIR_FREE(mac); + } + + ret = true; + +cleanup: + VIR_FREE(interfaces); + virDomainFree(dom); + VIR_FREE(xml); + xmlFreeDoc(xmldoc); + xmlXPathFreeContext(ctxt); + return ret; +} + +/* + * "domif-getlink" command + */ +static const vshCmdInfo info_domif_getlink[] = { + {"help", N_("get link state of a virtual interface")}, + {"desc", N_("Get link state of a domain's virtual interface.")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_domif_getlink[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, + {"persistent", VSH_OT_ALIAS, 0, "config"}, + {"config", VSH_OT_BOOL, 0, N_("Get persistent interface state")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfGetLink(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *iface = NULL; + int flags = 0; + char *state = NULL; + char *value = NULL; + virMacAddr macaddr; + const char *element; + const char *attr; + bool ret = false; + int i; + char *desc; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr cur = NULL; + xmlXPathObjectPtr obj = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptString(cmd, "interface", &iface) <= 0) { + virDomainFree(dom); + return false; + } + + if (vshCommandOptBool(cmd, "config")) + flags = VIR_DOMAIN_XML_INACTIVE; + + desc = virDomainGetXMLDesc(dom, flags); + if (desc == NULL) { + vshError(ctl, _("Failed to get domain description xml")); + goto cleanup; + } + + xml = virXMLParseStringCtxt(desc, _("(domain_definition)"), &ctxt); + VIR_FREE(desc); + if (!xml) { + vshError(ctl, _("Failed to parse domain description xml")); + goto cleanup; + } + + obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt); + if (obj == NULL || obj->type != XPATH_NODESET || + obj->nodesetval == NULL || obj->nodesetval->nodeNr == 0) { + vshError(ctl, _("Failed to extract interface information or no interfaces found")); + goto cleanup; + } + + if (virMacAddrParse(iface, &macaddr) == 0) { + element = "mac"; + attr = "address"; + } else { + element = "target"; + attr = "dev"; + } + + /* find interface with matching mac addr */ + for (i = 0; i < obj->nodesetval->nodeNr; i++) { + cur = obj->nodesetval->nodeTab[i]->children; + + while (cur) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST element)) { + + value = virXMLPropString(cur, attr); + + if (STRCASEEQ(value, iface)) { + VIR_FREE(value); + goto hit; + } + VIR_FREE(value); + } + cur = cur->next; + } + } + + vshError(ctl, _("Interface (%s: %s) not found."), element, iface); + goto cleanup; + +hit: + cur = obj->nodesetval->nodeTab[i]->children; + while (cur) { + if (cur->type == XML_ELEMENT_NODE && + xmlStrEqual(cur->name, BAD_CAST "link")) { + + state = virXMLPropString(cur, "state"); + vshPrint(ctl, "%s %s", iface, state); + VIR_FREE(state); + + goto cleanup; + } + cur = cur->next; + } + + /* attribute not found */ + vshPrint(ctl, "%s default", iface); + + ret = true; +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(xml); + if (dom) + virDomainFree(dom); + + return ret; +} + +/* + * "domcontrol" command + */ +static const vshCmdInfo info_domcontrol[] = { + {"help", N_("domain control interface state")}, + {"desc", N_("Returns state of a control interface to the domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domcontrol[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomControl(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = true; + virDomainControlInfo info; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (virDomainGetControlInfo(dom, &info, 0) < 0) { + ret = false; + goto cleanup; + } + + if (info.state != VIR_DOMAIN_CONTROL_OK && + info.state != VIR_DOMAIN_CONTROL_ERROR) { + vshPrint(ctl, "%s (%0.3fs)\n", + _(vshDomainControlStateToString(info.state)), + info.stateTime / 1000.0); + } else { + vshPrint(ctl, "%s\n", + _(vshDomainControlStateToString(info.state))); + } + +cleanup: + virDomainFree(dom); + return ret; +} + +/* + * "domblkstat" command + */ +static const vshCmdInfo info_domblkstat[] = { + {"help", N_("get device block stats for a domain")}, + {"desc", N_("Get device block stats for a running domain. See man page or " + "use --human for explanation of fields")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_domblkstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, + {"human", VSH_OT_BOOL, 0, N_("print a more human readable output")}, + {NULL, 0, 0, NULL} +}; + +struct _domblkstat_sequence { + const char *field; /* field name */ + const char *legacy; /* legacy name from previous releases */ + const char *human; /* human-friendly explanation */ +}; + +/* sequence of values for output to honor legacy format from previous + * versions */ +static const struct _domblkstat_sequence domblkstat_output[] = { + { VIR_DOMAIN_BLOCK_STATS_READ_REQ, "rd_req", + N_("number of read operations:") }, /* 0 */ + { VIR_DOMAIN_BLOCK_STATS_READ_BYTES, "rd_bytes", + N_("number of bytes read:") }, /* 1 */ + { VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "wr_req", + N_("number of write operations:") }, /* 2 */ + { VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, "wr_bytes", + N_("number of bytes written:") }, /* 3 */ + { VIR_DOMAIN_BLOCK_STATS_ERRS, "errs", + N_("error count:") }, /* 4 */ + { VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ, NULL, + N_("number of flush operations:") }, /* 5 */ + { VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES, NULL, + N_("total duration of reads (ns):") }, /* 6 */ + { VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES, NULL, + N_("total duration of writes (ns):") }, /* 7 */ + { VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES, NULL, + N_("total duration of flushes (ns):") }, /* 8 */ + { NULL, NULL, NULL } +}; + +#define DOMBLKSTAT_LEGACY_PRINT(ID, VALUE) \ + if (VALUE >= 0) \ + vshPrint(ctl, "%s %-*s %lld\n", device, \ + human ? 31 : 0, \ + human ? _(domblkstat_output[ID].human) \ + : domblkstat_output[ID].legacy, \ + VALUE); + +static bool +cmdDomblkstat(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name = NULL, *device = NULL; + struct _virDomainBlockStats stats; + virTypedParameterPtr params = NULL; + virTypedParameterPtr par = NULL; + char *value = NULL; + const char *field = NULL; + int rc, nparams = 0; + int i = 0; + bool ret = false; + bool human = vshCommandOptBool(cmd, "human"); /* human readable output */ + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + if (vshCommandOptString(cmd, "device", &device) <= 0) + goto cleanup; + + rc = virDomainBlockStatsFlags(dom, device, NULL, &nparams, 0); + + /* It might fail when virDomainBlockStatsFlags is not + * supported on older libvirt, fallback to use virDomainBlockStats + * then. + */ + if (rc < 0) { + /* try older API if newer is not supported */ + if (last_error->code != VIR_ERR_NO_SUPPORT) + goto cleanup; + + virFreeError(last_error); + last_error = NULL; + + if (virDomainBlockStats(dom, device, &stats, + sizeof(stats)) == -1) { + vshError(ctl, _("Failed to get block stats %s %s"), + name, device); + goto cleanup; + } + + /* human friendly output */ + if (human) { + vshPrint(ctl, N_("Device: %s\n"), device); + device = ""; + } + + DOMBLKSTAT_LEGACY_PRINT(0, stats.rd_req); + DOMBLKSTAT_LEGACY_PRINT(1, stats.rd_bytes); + DOMBLKSTAT_LEGACY_PRINT(2, stats.wr_req); + DOMBLKSTAT_LEGACY_PRINT(3, stats.wr_bytes); + DOMBLKSTAT_LEGACY_PRINT(4, stats.errs); + } else { + params = vshCalloc(ctl, nparams, sizeof(*params)); + + if (virDomainBlockStatsFlags(dom, device, params, &nparams, 0) < 0) { + vshError(ctl, _("Failed to get block stats %s %s"), name, device); + goto cleanup; + } + + /* set for prettier output */ + if (human) { + vshPrint(ctl, N_("Device: %s\n"), device); + device = ""; + } + + /* at first print all known values in desired order */ + for (i = 0; domblkstat_output[i].field != NULL; i++) { + if (!(par = vshFindTypedParamByName(domblkstat_output[i].field, + params, + nparams))) + continue; + + value = vshGetTypedParamValue(ctl, par); + + /* to print other not supported fields, mark the already printed */ + par->field[0] = '\0'; /* set the name to empty string */ + + /* translate into human readable or legacy spelling */ + field = NULL; + if (human) + field = _(domblkstat_output[i].human); + else + field = domblkstat_output[i].legacy; + + /* use the provided spelling if no translation is available */ + if (!field) + field = domblkstat_output[i].field; + + vshPrint(ctl, "%s %-*s %s\n", device, + human ? 31 : 0, field, value); + + VIR_FREE(value); + } + + /* go through the fields again, for remaining fields */ + for (i = 0; i < nparams; i++) { + if (!*params[i].field) + continue; + + value = vshGetTypedParamValue(ctl, params+i); + vshPrint(ctl, "%s %s %s\n", device, params[i].field, value); + VIR_FREE(value); + } + } + + ret = true; + +cleanup: + VIR_FREE(params); + virDomainFree(dom); + return ret; +} +#undef DOMBLKSTAT_LEGACY_PRINT + +/* + * "domifstat" command + */ +static const vshCmdInfo info_domifstat[] = { + {"help", N_("get network interface stats for a domain")}, + {"desc", N_("Get network interface stats for a running domain.")}, + {NULL,NULL} +}; + +static const vshCmdOptDef opts_domifstat[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomIfstat(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + const char *name = NULL, *device = NULL; + struct _virDomainInterfaceStats stats; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + if (vshCommandOptString(cmd, "interface", &device) <= 0) { + virDomainFree(dom); + return false; + } + + if (virDomainInterfaceStats(dom, device, &stats, sizeof(stats)) == -1) { + vshError(ctl, _("Failed to get interface stats %s %s"), name, device); + virDomainFree(dom); + return false; + } + + if (stats.rx_bytes >= 0) + vshPrint(ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes); + + if (stats.rx_packets >= 0) + vshPrint(ctl, "%s rx_packets %lld\n", device, stats.rx_packets); + + if (stats.rx_errs >= 0) + vshPrint(ctl, "%s rx_errs %lld\n", device, stats.rx_errs); + + if (stats.rx_drop >= 0) + vshPrint(ctl, "%s rx_drop %lld\n", device, stats.rx_drop); + + if (stats.tx_bytes >= 0) + vshPrint(ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes); + + if (stats.tx_packets >= 0) + vshPrint(ctl, "%s tx_packets %lld\n", device, stats.tx_packets); + + if (stats.tx_errs >= 0) + vshPrint(ctl, "%s tx_errs %lld\n", device, stats.tx_errs); + + if (stats.tx_drop >= 0) + vshPrint(ctl, "%s tx_drop %lld\n", device, stats.tx_drop); + + virDomainFree(dom); + return true; +} + +/* + * "domblkerror" command + */ +static const vshCmdInfo info_domblkerror[] = { + {"help", N_("Show errors on block devices")}, + {"desc", N_("Show block device errors")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domblkerror[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id, or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomBlkError(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + virDomainDiskErrorPtr disks = NULL; + unsigned int ndisks; + int i; + int count; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if ((count = virDomainGetDiskErrors(dom, NULL, 0, 0)) < 0) + goto cleanup; + ndisks = count; + + if (ndisks) { + if (VIR_ALLOC_N(disks, ndisks) < 0) + goto cleanup; + + if ((count = virDomainGetDiskErrors(dom, disks, ndisks, 0)) == -1) + goto cleanup; + } + + if (count == 0) { + vshPrint(ctl, _("No errors found\n")); + } else { + for (i = 0; i < count; i++) { + vshPrint(ctl, "%s: %s\n", + disks[i].disk, + vshDomainIOErrorToString(disks[i].error)); + } + } + + ret = true; + +cleanup: + VIR_FREE(disks); + virDomainFree(dom); + return ret; +} + +/* + * "dominfo" command + */ +static const vshCmdInfo info_dominfo[] = { + {"help", N_("domain information")}, + {"desc", N_("Returns basic information about the domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_dominfo[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDominfo(vshControl *ctl, const vshCmd *cmd) +{ + virDomainInfo info; + virDomainPtr dom; + virSecurityModel secmodel; + virSecurityLabelPtr seclabel; + int persistent = 0; + bool ret = true; + int autostart; + unsigned int id; + char *str, uuid[VIR_UUID_STRING_BUFLEN]; + int has_managed_save = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + id = virDomainGetID(dom); + if (id == ((unsigned int)-1)) + vshPrint(ctl, "%-15s %s\n", _("Id:"), "-"); + else + vshPrint(ctl, "%-15s %d\n", _("Id:"), id); + vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom)); + + if (virDomainGetUUIDString(dom, &uuid[0])==0) + vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); + + if ((str = virDomainGetOSType(dom))) { + vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str); + VIR_FREE(str); + } + + if (virDomainGetInfo(dom, &info) == 0) { + vshPrint(ctl, "%-15s %s\n", _("State:"), + _(vshDomainStateToString(info.state))); + + vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu); + + if (info.cpuTime != 0) { + double cpuUsed = info.cpuTime; + + cpuUsed /= 1000000000.0; + + vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed); + } + + if (info.maxMem != UINT_MAX) + vshPrint(ctl, "%-15s %lu KiB\n", _("Max memory:"), + info.maxMem); + else + vshPrint(ctl, "%-15s %s\n", _("Max memory:"), + _("no limit")); + + vshPrint(ctl, "%-15s %lu KiB\n", _("Used memory:"), + info.memory); + + } else { + ret = false; + } + + /* Check and display whether the domain is persistent or not */ + persistent = virDomainIsPersistent(dom); + vshDebug(ctl, VSH_ERR_DEBUG, "Domain persistent flag value: %d\n", + persistent); + if (persistent < 0) + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); + + /* Check and display whether the domain autostarts or not */ + if (!virDomainGetAutostart(dom, &autostart)) { + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), + autostart ? _("enable") : _("disable") ); + } + + has_managed_save = virDomainHasManagedSaveImage(dom, 0); + if (has_managed_save < 0) + vshPrint(ctl, "%-15s %s\n", _("Managed save:"), _("unknown")); + else + vshPrint(ctl, "%-15s %s\n", _("Managed save:"), + has_managed_save ? _("yes") : _("no")); + + /* Security model and label information */ + memset(&secmodel, 0, sizeof(secmodel)); + if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) { + if (last_error->code != VIR_ERR_NO_SUPPORT) { + virDomainFree(dom); + return false; + } else { + virFreeError(last_error); + last_error = NULL; + } + } else { + /* Only print something if a security model is active */ + if (secmodel.model[0] != '\0') { + vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model); + vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi); + + /* Security labels are only valid for active domains */ + if (VIR_ALLOC(seclabel) < 0) { + virDomainFree(dom); + return false; + } + + if (virDomainGetSecurityLabel(dom, seclabel) == -1) { + virDomainFree(dom); + VIR_FREE(seclabel); + return false; + } else { + if (seclabel->label[0] != '\0') + vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"), + seclabel->label, seclabel->enforcing ? "enforcing" : "permissive"); + } + + VIR_FREE(seclabel); + } + } + virDomainFree(dom); + return ret; +} + +/* + * "domstate" command + */ +static const vshCmdInfo info_domstate[] = { + {"help", N_("domain state")}, + {"desc", N_("Returns state about a domain.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_domstate[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"reason", VSH_OT_BOOL, 0, N_("also print reason for the state")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdDomstate(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + bool ret = true; + bool showReason = vshCommandOptBool(cmd, "reason"); + int state, reason; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if ((state = vshDomainState(ctl, dom, &reason)) < 0) { + ret = false; + goto cleanup; + } + + if (showReason) { + vshPrint(ctl, "%s (%s)\n", + _(vshDomainStateToString(state)), + vshDomainStateReasonToString(state, reason)); + } else { + vshPrint(ctl, "%s\n", + _(vshDomainStateToString(state))); + } + +cleanup: + virDomainFree(dom); + return ret; +} + +/* + * "list" command + */ +static const vshCmdInfo info_list[] = { + {"help", N_("list domains")}, + {"desc", N_("Returns list of domains.")}, + {NULL, NULL} +}; + +/* compare domains, pack NULLed ones at the end*/ +static int +vshDomainSorter(const void *a, const void *b) +{ + virDomainPtr *da = (virDomainPtr *) a; + virDomainPtr *db = (virDomainPtr *) b; + unsigned int ida; + unsigned int idb; + unsigned int inactive = (unsigned int) -1; + + if (*da && !*db) + return -1; + + if (!*da) + return *db != NULL; + + ida = virDomainGetID(*da); + idb = virDomainGetID(*db); + + if (ida == inactive && idb == inactive) + return strcasecmp(virDomainGetName(*da), virDomainGetName(*db)); + + if (ida != inactive && idb != inactive) { + if (ida > idb) + return 1; + else if (ida < idb) + return -1; + } + + if (ida != inactive) + return -1; + else + return 1; +} + +struct vshDomainList { + virDomainPtr *domains; + size_t ndomains; +}; +typedef struct vshDomainList *vshDomainListPtr; + +static void +vshDomainListFree(vshDomainListPtr domlist) +{ + int i; + + if (domlist && domlist->domains) { + for (i = 0; i < domlist->ndomains; i++) { + if (domlist->domains[i]) + virDomainFree(domlist->domains[i]); + } + VIR_FREE(domlist->domains); + } + VIR_FREE(domlist); +} + +#define MATCH(FLAG) (flags & (FLAG)) +static vshDomainListPtr +vshDomainListCollect(vshControl *ctl, unsigned int flags) +{ + vshDomainListPtr list = vshMalloc(ctl, sizeof(*list)); + int i; + int ret; + int *ids = NULL; + int nids = 0; + char **names = NULL; + int nnames = 0; + virDomainPtr dom; + bool success = false; + size_t deleted = 0; + int persistent; + int autostart; + int state; + int nsnap; + int mansave; + + /* try the list with flags support (0.9.13 and later) */ + if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, + flags)) >= 0) { + list->ndomains = ret; + goto finished; + } + + /* check if the command is actually supported */ + if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { + virFreeError(last_error); + last_error = NULL; + goto fallback; + } + + if (last_error && last_error->code == VIR_ERR_INVALID_ARG) { + /* try the new API again but mask non-guaranteed flags */ + unsigned int newflags = flags & (VIR_CONNECT_LIST_DOMAINS_ACTIVE | + VIR_CONNECT_LIST_DOMAINS_INACTIVE); + + virFreeError(last_error); + last_error = NULL; + if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, + newflags)) >= 0) { + list->ndomains = ret; + goto filter; + } + } + + /* there was an error during the first or second call */ + vshError(ctl, "%s", _("Failed to list domains")); + goto cleanup; + + +fallback: + /* fall back to old method (0.9.12 and older) */ + virResetLastError(); + + /* list active domains, if necessary */ + if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE)) { + if ((nids = virConnectNumOfDomains(ctl->conn)) < 0) { + vshError(ctl, "%s", _("Failed to list active domains")); + goto cleanup; + } + + if (nids) { + ids = vshMalloc(ctl, sizeof(int) * nids); + + if ((nids = virConnectListDomains(ctl->conn, ids, nids)) < 0) { + vshError(ctl, "%s", _("Failed to list active domains")); + goto cleanup; + } + } + } + + if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || + MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE)) { + if ((nnames = virConnectNumOfDefinedDomains(ctl->conn)) < 0) { + vshError(ctl, "%s", _("Failed to list inactive domains")); + goto cleanup; + } + + if (nnames) { + names = vshMalloc(ctl, sizeof(char *) * nnames); + + if ((nnames = virConnectListDefinedDomains(ctl->conn, names, + nnames)) < 0) { + vshError(ctl, "%s", _("Failed to list inactive domains")); + goto cleanup; + } + } + } + + list->domains = vshMalloc(ctl, sizeof(virDomainPtr) * (nids + nnames)); + list->ndomains = 0; + + /* get active domains */ + for (i = 0; i < nids; i++) { + if (!(dom = virDomainLookupByID(ctl->conn, ids[i]))) + continue; + list->domains[list->ndomains++] = dom; + } + + /* get inactive domains */ + for (i = 0; i < nnames; i++) { + if (!(dom = virDomainLookupByName(ctl->conn, names[i]))) + continue; + list->domains[list->ndomains++] = dom; + } + + /* truncate domains that weren't found */ + deleted = (nids + nnames) - list->ndomains; + +filter: + /* filter list the list if the list was acquired by fallback means */ + for (i = 0; i < list->ndomains; i++) { + dom = list->domains[i]; + + /* persistence filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_PERSISTENT)) { + if ((persistent = virDomainIsPersistent(dom)) < 0) { + vshError(ctl, "%s", _("Failed to get domain persistence info")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) && persistent) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && !persistent))) + goto remove_entry; + } + + /* domain state filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_STATE)) { + if (virDomainGetState(dom, &state, NULL, 0) < 0) { + vshError(ctl, "%s", _("Failed to get domain state")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && + state == VIR_DOMAIN_RUNNING) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) && + state == VIR_DOMAIN_PAUSED) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) && + state == VIR_DOMAIN_SHUTOFF) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) && + (state != VIR_DOMAIN_RUNNING && + state != VIR_DOMAIN_PAUSED && + state != VIR_DOMAIN_SHUTOFF)))) + goto remove_entry; + } + + /* autostart filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_AUTOSTART)) { + if (virDomainGetAutostart(dom, &autostart) < 0) { + vshError(ctl, "%s", _("Failed to get domain autostart state")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && autostart) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !autostart))) + goto remove_entry; + } + + /* managed save filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE)) { + if ((mansave = virDomainHasManagedSaveImage(dom, 0)) < 0) { + vshError(ctl, "%s", + _("Failed to check for managed save image")); + goto cleanup; + } + + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) && !mansave))) + goto remove_entry; + } + + /* snapshot filter */ + if (MATCH(VIR_CONNECT_LIST_FILTERS_SNAPSHOT)) { + if ((nsnap = virDomainSnapshotNum(dom, 0)) < 0) { + vshError(ctl, "%s", _("Failed to get snapshot count")); + goto cleanup; + } + if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) || + (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap == 0))) + goto remove_entry; + } + + /* the domain matched all filters, it may stay */ + continue; + +remove_entry: + /* the domain has to be removed as it failed one of the filters */ + virDomainFree(list->domains[i]); + list->domains[i] = NULL; + deleted++; + } + +finished: + /* sort the list */ + if (list->domains && list->ndomains) + qsort(list->domains, list->ndomains, sizeof(*list->domains), + vshDomainSorter); + + /* truncate the list if filter simulation deleted entries */ + if (deleted) + VIR_SHRINK_N(list->domains, list->ndomains, deleted); + + success = true; + +cleanup: + for (i = 0; i < nnames; i++) + VIR_FREE(names[i]); + + if (!success) { + vshDomainListFree(list); + list = NULL; + } + + VIR_FREE(names); + VIR_FREE(ids); + return list; +} +#undef MATCH + +static const vshCmdOptDef opts_list[] = { + {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")}, + {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")}, + {"transient", VSH_OT_BOOL, 0, N_("list transient domains")}, + {"persistent", VSH_OT_BOOL, 0, N_("list persistent domains")}, + {"with-snapshot", VSH_OT_BOOL, 0, + N_("list domains with existing snapshot")}, + {"without-snapshot", VSH_OT_BOOL, 0, + N_("list domains without a snapshot")}, + {"state-running", VSH_OT_BOOL, 0, N_("list domains in running state")}, + {"state-paused", VSH_OT_BOOL, 0, N_("list domains in paused state")}, + {"state-shutoff", VSH_OT_BOOL, 0, N_("list domains in shutoff state")}, + {"state-other", VSH_OT_BOOL, 0, N_("list domains in other states")}, + {"autostart", VSH_OT_BOOL, 0, N_("list domains with autostart enabled")}, + {"no-autostart", VSH_OT_BOOL, 0, + N_("list domains with autostart disabled")}, + {"with-managed-save", VSH_OT_BOOL, 0, + N_("list domains with managed save state")}, + {"without-managed-save", VSH_OT_BOOL, 0, + N_("list domains without managed save")}, + {"uuid", VSH_OT_BOOL, 0, N_("list uuid's only")}, + {"name", VSH_OT_BOOL, 0, N_("list domain names only")}, + {"table", VSH_OT_BOOL, 0, N_("list table (default)")}, + {"managed-save", VSH_OT_BOOL, 0, + N_("mark inactive domains with managed save state")}, + {"title", VSH_OT_BOOL, 0, N_("show short domain description")}, + {NULL, 0, 0, NULL} +}; + +#define FILTER(NAME, FLAG) \ + if (vshCommandOptBool(cmd, NAME)) \ + flags |= (FLAG) +static bool +cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + bool managed = vshCommandOptBool(cmd, "managed-save"); + bool optTitle = vshCommandOptBool(cmd, "title"); + bool optTable = vshCommandOptBool(cmd, "table"); + bool optUUID = vshCommandOptBool(cmd, "uuid"); + bool optName = vshCommandOptBool(cmd, "name"); + int i; + char *title; + char uuid[VIR_UUID_STRING_BUFLEN]; + int state; + bool ret = false; + vshDomainListPtr list = NULL; + virDomainPtr dom; + char id_buf[INT_BUFSIZE_BOUND(unsigned int)]; + unsigned int id; + unsigned int flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE; + + /* construct filter flags */ + if (vshCommandOptBool(cmd, "inactive")) + flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE; + + if (vshCommandOptBool(cmd, "all")) + flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE | + VIR_CONNECT_LIST_DOMAINS_ACTIVE; + + FILTER("persistent", VIR_CONNECT_LIST_DOMAINS_PERSISTENT); + FILTER("transient", VIR_CONNECT_LIST_DOMAINS_TRANSIENT); + + FILTER("with-managed-save", VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE); + FILTER("without-managed-save", VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE); + + FILTER("autostart", VIR_CONNECT_LIST_DOMAINS_AUTOSTART); + FILTER("no-autostart", VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART); + + FILTER("with-snapshot", VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT); + FILTER("without-snapshot", VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT); + + FILTER("state-running", VIR_CONNECT_LIST_DOMAINS_RUNNING); + FILTER("state-paused", VIR_CONNECT_LIST_DOMAINS_PAUSED); + FILTER("state-shutoff", VIR_CONNECT_LIST_DOMAINS_SHUTOFF); + FILTER("state-other", VIR_CONNECT_LIST_DOMAINS_OTHER); + + if (optTable + optName + optUUID > 1) { + vshError(ctl, "%s", + _("Only one argument from --table, --name and --uuid " + "may be specified.")); + return false; + } + + if (!optUUID && !optName) + optTable = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(list = vshDomainListCollect(ctl, flags))) + goto cleanup; + + /* print table header in legacy mode */ + if (optTable) { + if (optTitle) + vshPrintExtra(ctl, " %-5s %-30s %-10s %-20s\n%s\n", + _("Id"), _("Name"), _("State"), _("Title"), + "-----------------------------------------" + "-----------------------------------------"); + else + vshPrintExtra(ctl, " %-5s %-30s %s\n%s\n", + _("Id"), _("Name"), _("State"), + "-----------------------------------------" + "-----------"); + } + + for (i = 0; i < list->ndomains; i++) { + dom = list->domains[i]; + id = virDomainGetID(dom); + if (id != (unsigned int) -1) + snprintf(id_buf, sizeof(id_buf), "%d", id); + else + ignore_value(virStrcpyStatic(id_buf, "-")); + + state = vshDomainState(ctl, dom, NULL); + if (optTable && managed && state == VIR_DOMAIN_SHUTOFF && + virDomainHasManagedSaveImage(dom, 0) > 0) + state = -2; + + if (optTable) { + if (optTitle) { + if (!(title = vshGetDomainDescription(ctl, dom, true, 0))) + goto cleanup; + + vshPrint(ctl, " %-5s %-30s %-10s %-20s\n", id_buf, + virDomainGetName(dom), + state == -2 ? _("saved") : _(vshDomainStateToString(state)), + title); + + VIR_FREE(title); + } else { + vshPrint(ctl, " %-5s %-30s %s\n", id_buf, + virDomainGetName(dom), + state == -2 ? _("saved") : _(vshDomainStateToString(state))); + } + } else if (optUUID) { + if (virDomainGetUUIDString(dom, uuid) < 0) { + vshError(ctl, "%s", _("Failed to get domain's UUID")); + goto cleanup; + } + vshPrint(ctl, "%s\n", uuid); + } else if (optName) { + vshPrint(ctl, "%s\n", virDomainGetName(dom)); + } + } + + ret = true; +cleanup: + vshDomainListFree(list); + return ret; +} +#undef FILTER diff --git a/tools/virsh.c b/tools/virsh.c index 81976a0..85c171b 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -976,450 +976,6 @@ cleanup: #endif /* WIN32 */ - -/* - * "list" command - */ -static const vshCmdInfo info_list[] = { - {"help", N_("list domains")}, - {"desc", N_("Returns list of domains.")}, - {NULL, NULL} -}; - -/* compare domains, pack NULLed ones at the end*/ -static int -vshDomainSorter(const void *a, const void *b) -{ - virDomainPtr *da = (virDomainPtr *) a; - virDomainPtr *db = (virDomainPtr *) b; - unsigned int ida; - unsigned int idb; - unsigned int inactive = (unsigned int) -1; - - if (*da && !*db) - return -1; - - if (!*da) - return *db != NULL; - - ida = virDomainGetID(*da); - idb = virDomainGetID(*db); - - if (ida == inactive && idb == inactive) - return strcasecmp(virDomainGetName(*da), virDomainGetName(*db)); - - if (ida != inactive && idb != inactive) { - if (ida > idb) - return 1; - else if (ida < idb) - return -1; - } - - if (ida != inactive) - return -1; - else - return 1; -} - -struct vshDomainList { - virDomainPtr *domains; - size_t ndomains; -}; -typedef struct vshDomainList *vshDomainListPtr; - -static void -vshDomainListFree(vshDomainListPtr domlist) -{ - int i; - - if (domlist && domlist->domains) { - for (i = 0; i < domlist->ndomains; i++) { - if (domlist->domains[i]) - virDomainFree(domlist->domains[i]); - } - VIR_FREE(domlist->domains); - } - VIR_FREE(domlist); -} - -#define MATCH(FLAG) (flags & (FLAG)) -static vshDomainListPtr -vshDomainListCollect(vshControl *ctl, unsigned int flags) -{ - vshDomainListPtr list = vshMalloc(ctl, sizeof(*list)); - int i; - int ret; - int *ids = NULL; - int nids = 0; - char **names = NULL; - int nnames = 0; - virDomainPtr dom; - bool success = false; - size_t deleted = 0; - int persistent; - int autostart; - int state; - int nsnap; - int mansave; - - /* try the list with flags support (0.9.13 and later) */ - if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, - flags)) >= 0) { - list->ndomains = ret; - goto finished; - } - - /* check if the command is actually supported */ - if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) { - virFreeError(last_error); - last_error = NULL; - goto fallback; - } - - if (last_error && last_error->code == VIR_ERR_INVALID_ARG) { - /* try the new API again but mask non-guaranteed flags */ - unsigned int newflags = flags & (VIR_CONNECT_LIST_DOMAINS_ACTIVE | - VIR_CONNECT_LIST_DOMAINS_INACTIVE); - - virFreeError(last_error); - last_error = NULL; - if ((ret = virConnectListAllDomains(ctl->conn, &list->domains, - newflags)) >= 0) { - list->ndomains = ret; - goto filter; - } - } - - /* there was an error during the first or second call */ - vshError(ctl, "%s", _("Failed to list domains")); - goto cleanup; - - -fallback: - /* fall back to old method (0.9.12 and older) */ - virResetLastError(); - - /* list active domains, if necessary */ - if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || - MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE)) { - if ((nids = virConnectNumOfDomains(ctl->conn)) < 0) { - vshError(ctl, "%s", _("Failed to list active domains")); - goto cleanup; - } - - if (nids) { - ids = vshMalloc(ctl, sizeof(int) * nids); - - if ((nids = virConnectListDomains(ctl->conn, ids, nids)) < 0) { - vshError(ctl, "%s", _("Failed to list active domains")); - goto cleanup; - } - } - } - - if (!MATCH(VIR_CONNECT_LIST_FILTERS_ACTIVE) || - MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE)) { - if ((nnames = virConnectNumOfDefinedDomains(ctl->conn)) < 0) { - vshError(ctl, "%s", _("Failed to list inactive domains")); - goto cleanup; - } - - if (nnames) { - names = vshMalloc(ctl, sizeof(char *) * nnames); - - if ((nnames = virConnectListDefinedDomains(ctl->conn, names, - nnames)) < 0) { - vshError(ctl, "%s", _("Failed to list inactive domains")); - goto cleanup; - } - } - } - - list->domains = vshMalloc(ctl, sizeof(virDomainPtr) * (nids + nnames)); - list->ndomains = 0; - - /* get active domains */ - for (i = 0; i < nids; i++) { - if (!(dom = virDomainLookupByID(ctl->conn, ids[i]))) - continue; - list->domains[list->ndomains++] = dom; - } - - /* get inactive domains */ - for (i = 0; i < nnames; i++) { - if (!(dom = virDomainLookupByName(ctl->conn, names[i]))) - continue; - list->domains[list->ndomains++] = dom; - } - - /* truncate domains that weren't found */ - deleted = (nids + nnames) - list->ndomains; - -filter: - /* filter list the list if the list was acquired by fallback means */ - for (i = 0; i < list->ndomains; i++) { - dom = list->domains[i]; - - /* persistence filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_PERSISTENT)) { - if ((persistent = virDomainIsPersistent(dom)) < 0) { - vshError(ctl, "%s", _("Failed to get domain persistence info")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) && persistent) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && !persistent))) - goto remove_entry; - } - - /* domain state filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_STATE)) { - if (virDomainGetState(dom, &state, NULL, 0) < 0) { - vshError(ctl, "%s", _("Failed to get domain state")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) && - state == VIR_DOMAIN_RUNNING) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) && - state == VIR_DOMAIN_PAUSED) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) && - state == VIR_DOMAIN_SHUTOFF) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) && - (state != VIR_DOMAIN_RUNNING && - state != VIR_DOMAIN_PAUSED && - state != VIR_DOMAIN_SHUTOFF)))) - goto remove_entry; - } - - /* autostart filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_AUTOSTART)) { - if (virDomainGetAutostart(dom, &autostart) < 0) { - vshError(ctl, "%s", _("Failed to get domain autostart state")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && autostart) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !autostart))) - goto remove_entry; - } - - /* managed save filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_MANAGEDSAVE)) { - if ((mansave = virDomainHasManagedSaveImage(dom, 0)) < 0) { - vshError(ctl, "%s", - _("Failed to check for managed save image")); - goto cleanup; - } - - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) && !mansave))) - goto remove_entry; - } - - /* snapshot filter */ - if (MATCH(VIR_CONNECT_LIST_FILTERS_SNAPSHOT)) { - if ((nsnap = virDomainSnapshotNum(dom, 0)) < 0) { - vshError(ctl, "%s", _("Failed to get snapshot count")); - goto cleanup; - } - if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) || - (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap == 0))) - goto remove_entry; - } - - /* the domain matched all filters, it may stay */ - continue; - -remove_entry: - /* the domain has to be removed as it failed one of the filters */ - virDomainFree(list->domains[i]); - list->domains[i] = NULL; - deleted++; - } - -finished: - /* sort the list */ - if (list->domains && list->ndomains) - qsort(list->domains, list->ndomains, sizeof(*list->domains), - vshDomainSorter); - - /* truncate the list if filter simulation deleted entries */ - if (deleted) - VIR_SHRINK_N(list->domains, list->ndomains, deleted); - - success = true; - -cleanup: - for (i = 0; i < nnames; i++) - VIR_FREE(names[i]); - - if (!success) { - vshDomainListFree(list); - list = NULL; - } - - VIR_FREE(names); - VIR_FREE(ids); - return list; -} -#undef MATCH - - -static const vshCmdOptDef opts_list[] = { - {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")}, - {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")}, - {"transient", VSH_OT_BOOL, 0, N_("list transient domains")}, - {"persistent", VSH_OT_BOOL, 0, N_("list persistent domains")}, - {"with-snapshot", VSH_OT_BOOL, 0, - N_("list domains with existing snapshot")}, - {"without-snapshot", VSH_OT_BOOL, 0, - N_("list domains without a snapshot")}, - {"state-running", VSH_OT_BOOL, 0, N_("list domains in running state")}, - {"state-paused", VSH_OT_BOOL, 0, N_("list domains in paused state")}, - {"state-shutoff", VSH_OT_BOOL, 0, N_("list domains in shutoff state")}, - {"state-other", VSH_OT_BOOL, 0, N_("list domains in other states")}, - {"autostart", VSH_OT_BOOL, 0, N_("list domains with autostart enabled")}, - {"no-autostart", VSH_OT_BOOL, 0, - N_("list domains with autostart disabled")}, - {"with-managed-save", VSH_OT_BOOL, 0, - N_("list domains with managed save state")}, - {"without-managed-save", VSH_OT_BOOL, 0, - N_("list domains without managed save")}, - {"uuid", VSH_OT_BOOL, 0, N_("list uuid's only")}, - {"name", VSH_OT_BOOL, 0, N_("list domain names only")}, - {"table", VSH_OT_BOOL, 0, N_("list table (default)")}, - {"managed-save", VSH_OT_BOOL, 0, - N_("mark inactive domains with managed save state")}, - {"title", VSH_OT_BOOL, 0, N_("show short domain description")}, - {NULL, 0, 0, NULL} -}; - - -#define FILTER(NAME, FLAG) \ - if (vshCommandOptBool(cmd, NAME)) \ - flags |= (FLAG) -static bool -cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - bool managed = vshCommandOptBool(cmd, "managed-save"); - bool optTitle = vshCommandOptBool(cmd, "title"); - bool optTable = vshCommandOptBool(cmd, "table"); - bool optUUID = vshCommandOptBool(cmd, "uuid"); - bool optName = vshCommandOptBool(cmd, "name"); - int i; - char *title; - char uuid[VIR_UUID_STRING_BUFLEN]; - int state; - bool ret = false; - vshDomainListPtr list = NULL; - virDomainPtr dom; - char id_buf[INT_BUFSIZE_BOUND(unsigned int)]; - unsigned int id; - unsigned int flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE; - - /* construct filter flags */ - if (vshCommandOptBool(cmd, "inactive")) - flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE; - - if (vshCommandOptBool(cmd, "all")) - flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE | - VIR_CONNECT_LIST_DOMAINS_ACTIVE; - - FILTER("persistent", VIR_CONNECT_LIST_DOMAINS_PERSISTENT); - FILTER("transient", VIR_CONNECT_LIST_DOMAINS_TRANSIENT); - - FILTER("with-managed-save", VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE); - FILTER("without-managed-save", VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE); - - FILTER("autostart", VIR_CONNECT_LIST_DOMAINS_AUTOSTART); - FILTER("no-autostart", VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART); - - FILTER("with-snapshot", VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT); - FILTER("without-snapshot", VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT); - - FILTER("state-running", VIR_CONNECT_LIST_DOMAINS_RUNNING); - FILTER("state-paused", VIR_CONNECT_LIST_DOMAINS_PAUSED); - FILTER("state-shutoff", VIR_CONNECT_LIST_DOMAINS_SHUTOFF); - FILTER("state-other", VIR_CONNECT_LIST_DOMAINS_OTHER); - - if (optTable + optName + optUUID > 1) { - vshError(ctl, "%s", - _("Only one argument from --table, --name and --uuid " - "may be specified.")); - return false; - } - - if (!optUUID && !optName) - optTable = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(list = vshDomainListCollect(ctl, flags))) - goto cleanup; - - /* print table header in legacy mode */ - if (optTable) { - if (optTitle) - vshPrintExtra(ctl, " %-5s %-30s %-10s %-20s\n%s\n", - _("Id"), _("Name"), _("State"), _("Title"), - "-----------------------------------------" - "-----------------------------------------"); - else - vshPrintExtra(ctl, " %-5s %-30s %s\n%s\n", - _("Id"), _("Name"), _("State"), - "-----------------------------------------" - "-----------"); - } - - for (i = 0; i < list->ndomains; i++) { - dom = list->domains[i]; - id = virDomainGetID(dom); - if (id != (unsigned int) -1) - snprintf(id_buf, sizeof(id_buf), "%d", id); - else - ignore_value(virStrcpyStatic(id_buf, "-")); - - state = vshDomainState(ctl, dom, NULL); - if (optTable && managed && state == VIR_DOMAIN_SHUTOFF && - virDomainHasManagedSaveImage(dom, 0) > 0) - state = -2; - - if (optTable) { - if (optTitle) { - if (!(title = vshGetDomainDescription(ctl, dom, true, 0))) - goto cleanup; - - vshPrint(ctl, " %-5s %-30s %-10s %-20s\n", id_buf, - virDomainGetName(dom), - state == -2 ? _("saved") : _(vshDomainStateToString(state)), - title); - - VIR_FREE(title); - } else { - vshPrint(ctl, " %-5s %-30s %s\n", id_buf, - virDomainGetName(dom), - state == -2 ? _("saved") : _(vshDomainStateToString(state))); - } - } else if (optUUID) { - if (virDomainGetUUIDString(dom, uuid) < 0) { - vshError(ctl, "%s", _("Failed to get domain's UUID")); - goto cleanup; - } - vshPrint(ctl, "%s\n", uuid); - } else if (optName) { - vshPrint(ctl, "%s\n", virDomainGetName(dom)); - } - } - - ret = true; -cleanup: - vshDomainListFree(list); - return ret; -} -#undef FILTER - /* * "desc" command for managing domain description and title */ @@ -1576,28 +1132,43 @@ cleanup: return ret; } -/* - * "domstate" command +/* "domif-setlink" command */ -static const vshCmdInfo info_domstate[] = { - {"help", N_("domain state")}, - {"desc", N_("Returns state about a domain.")}, - {NULL, NULL} +static const vshCmdInfo info_domif_setlink[] = { + {"help", N_("set link state of a virtual interface")}, + {"desc", N_("Set link state of a domain's virtual interface. This command wraps usage of update-device command.")}, + {NULL,NULL} }; -static const vshCmdOptDef opts_domstate[] = { +static const vshCmdOptDef opts_domif_setlink[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"reason", VSH_OT_BOOL, 0, N_("also print reason for the state")}, + {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, + {"state", VSH_OT_DATA, VSH_OFLAG_REQ, N_("new state of the device")}, + {"persistent", VSH_OT_ALIAS, 0, "config"}, + {"config", VSH_OT_BOOL, 0, N_("affect next boot")}, {NULL, 0, 0, NULL} }; static bool -cmdDomstate(vshControl *ctl, const vshCmd *cmd) +cmdDomIfSetLink(vshControl *ctl, const vshCmd *cmd) { virDomainPtr dom; - bool ret = true; - bool showReason = vshCommandOptBool(cmd, "reason"); - int state, reason; + const char *iface; + const char *state; + const char *value; + const char *desc; + virMacAddr macaddr; + const char *element; + const char *attr; + bool config; + bool ret = false; + unsigned int flags = 0; + int i; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + xmlNodePtr cur = NULL; + xmlBufferPtr xml_buf = NULL; if (!vshConnectionUsability(ctl, ctl->conn)) return false; @@ -1605,382 +1176,33 @@ cmdDomstate(vshControl *ctl, const vshCmd *cmd) if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) return false; - if ((state = vshDomainState(ctl, dom, &reason)) < 0) { - ret = false; + if (vshCommandOptString(cmd, "interface", &iface) <= 0) goto cleanup; - } - - if (showReason) { - vshPrint(ctl, "%s (%s)\n", - _(vshDomainStateToString(state)), - vshDomainStateReasonToString(state, reason)); - } else { - vshPrint(ctl, "%s\n", - _(vshDomainStateToString(state))); - } - -cleanup: - virDomainFree(dom); - return ret; -} - -/* - * "domcontrol" command - */ -static const vshCmdInfo info_domcontrol[] = { - {"help", N_("domain control interface state")}, - {"desc", N_("Returns state of a control interface to the domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domcontrol[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomControl(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - bool ret = true; - virDomainControlInfo info; - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; + if (vshCommandOptString(cmd, "state", &state) <= 0) + goto cleanup; - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; + config = vshCommandOptBool(cmd, "config"); - if (virDomainGetControlInfo(dom, &info, 0) < 0) { - ret = false; + if (STRNEQ(state, "up") && STRNEQ(state, "down")) { + vshError(ctl, _("invalid link state '%s'"), state); goto cleanup; } - if (info.state != VIR_DOMAIN_CONTROL_OK && - info.state != VIR_DOMAIN_CONTROL_ERROR) { - vshPrint(ctl, "%s (%0.3fs)\n", - _(vshDomainControlStateToString(info.state)), - info.stateTime / 1000.0); - } else { - vshPrint(ctl, "%s\n", - _(vshDomainControlStateToString(info.state))); + /* get persistent or live description of network device */ + desc = virDomainGetXMLDesc(dom, config ? VIR_DOMAIN_XML_INACTIVE : 0); + if (desc == NULL) { + vshError(ctl, _("Failed to get domain description xml")); + goto cleanup; } -cleanup: - virDomainFree(dom); - return ret; -} + if (config) + flags = VIR_DOMAIN_AFFECT_CONFIG; + else + flags = VIR_DOMAIN_AFFECT_LIVE; -/* "domblkstat" command - */ -static const vshCmdInfo info_domblkstat[] = { - {"help", N_("get device block stats for a domain")}, - {"desc", N_("Get device block stats for a running domain. See man page or " - "use --human for explanation of fields")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domblkstat[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, - {"human", VSH_OT_BOOL, 0, N_("print a more human readable output")}, - {NULL, 0, 0, NULL} -}; - -struct _domblkstat_sequence { - const char *field; /* field name */ - const char *legacy; /* legacy name from previous releases */ - const char *human; /* human-friendly explanation */ -}; - -/* sequence of values for output to honor legacy format from previous - * versions */ -static const struct _domblkstat_sequence domblkstat_output[] = { - { VIR_DOMAIN_BLOCK_STATS_READ_REQ, "rd_req", - N_("number of read operations:") }, /* 0 */ - { VIR_DOMAIN_BLOCK_STATS_READ_BYTES, "rd_bytes", - N_("number of bytes read:") }, /* 1 */ - { VIR_DOMAIN_BLOCK_STATS_WRITE_REQ, "wr_req", - N_("number of write operations:") }, /* 2 */ - { VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES, "wr_bytes", - N_("number of bytes written:") }, /* 3 */ - { VIR_DOMAIN_BLOCK_STATS_ERRS, "errs", - N_("error count:") }, /* 4 */ - { VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ, NULL, - N_("number of flush operations:") }, /* 5 */ - { VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES, NULL, - N_("total duration of reads (ns):") }, /* 6 */ - { VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES, NULL, - N_("total duration of writes (ns):") }, /* 7 */ - { VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES, NULL, - N_("total duration of flushes (ns):") }, /* 8 */ - { NULL, NULL, NULL } -}; - -#define DOMBLKSTAT_LEGACY_PRINT(ID, VALUE) \ - if (VALUE >= 0) \ - vshPrint(ctl, "%s %-*s %lld\n", device, \ - human ? 31 : 0, \ - human ? _(domblkstat_output[ID].human) \ - : domblkstat_output[ID].legacy, \ - VALUE); - -static bool -cmdDomblkstat(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *name = NULL, *device = NULL; - struct _virDomainBlockStats stats; - virTypedParameterPtr params = NULL; - virTypedParameterPtr par = NULL; - char *value = NULL; - const char *field = NULL; - int rc, nparams = 0; - int i = 0; - bool ret = false; - bool human = vshCommandOptBool(cmd, "human"); /* human readable output */ - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; - - if (vshCommandOptString(cmd, "device", &device) <= 0) - goto cleanup; - - rc = virDomainBlockStatsFlags(dom, device, NULL, &nparams, 0); - - /* It might fail when virDomainBlockStatsFlags is not - * supported on older libvirt, fallback to use virDomainBlockStats - * then. - */ - if (rc < 0) { - /* try older API if newer is not supported */ - if (last_error->code != VIR_ERR_NO_SUPPORT) - goto cleanup; - - virFreeError(last_error); - last_error = NULL; - - if (virDomainBlockStats(dom, device, &stats, - sizeof(stats)) == -1) { - vshError(ctl, _("Failed to get block stats %s %s"), - name, device); - goto cleanup; - } - - /* human friendly output */ - if (human) { - vshPrint(ctl, N_("Device: %s\n"), device); - device = ""; - } - - DOMBLKSTAT_LEGACY_PRINT(0, stats.rd_req); - DOMBLKSTAT_LEGACY_PRINT(1, stats.rd_bytes); - DOMBLKSTAT_LEGACY_PRINT(2, stats.wr_req); - DOMBLKSTAT_LEGACY_PRINT(3, stats.wr_bytes); - DOMBLKSTAT_LEGACY_PRINT(4, stats.errs); - } else { - params = vshCalloc(ctl, nparams, sizeof(*params)); - - if (virDomainBlockStatsFlags(dom, device, params, &nparams, 0) < 0) { - vshError(ctl, _("Failed to get block stats %s %s"), name, device); - goto cleanup; - } - - /* set for prettier output */ - if (human) { - vshPrint(ctl, N_("Device: %s\n"), device); - device = ""; - } - - /* at first print all known values in desired order */ - for (i = 0; domblkstat_output[i].field != NULL; i++) { - if (!(par = vshFindTypedParamByName(domblkstat_output[i].field, - params, - nparams))) - continue; - - value = vshGetTypedParamValue(ctl, par); - - /* to print other not supported fields, mark the already printed */ - par->field[0] = '\0'; /* set the name to empty string */ - - /* translate into human readable or legacy spelling */ - field = NULL; - if (human) - field = _(domblkstat_output[i].human); - else - field = domblkstat_output[i].legacy; - - /* use the provided spelling if no translation is available */ - if (!field) - field = domblkstat_output[i].field; - - vshPrint(ctl, "%s %-*s %s\n", device, - human ? 31 : 0, field, value); - - VIR_FREE(value); - } - - /* go through the fields again, for remaining fields */ - for (i = 0; i < nparams; i++) { - if (!*params[i].field) - continue; - - value = vshGetTypedParamValue(ctl, params+i); - vshPrint(ctl, "%s %s %s\n", device, params[i].field, value); - VIR_FREE(value); - } - } - - ret = true; - -cleanup: - VIR_FREE(params); - virDomainFree(dom); - return ret; -} -#undef DOMBLKSTAT_LEGACY_PRINT - -/* "domifstat" command - */ -static const vshCmdInfo info_domifstat[] = { - {"help", N_("get network interface stats for a domain")}, - {"desc", N_("Get network interface stats for a running domain.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domifstat[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomIfstat(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *name = NULL, *device = NULL; - struct _virDomainInterfaceStats stats; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; - - if (vshCommandOptString(cmd, "interface", &device) <= 0) { - virDomainFree(dom); - return false; - } - - if (virDomainInterfaceStats(dom, device, &stats, sizeof(stats)) == -1) { - vshError(ctl, _("Failed to get interface stats %s %s"), name, device); - virDomainFree(dom); - return false; - } - - if (stats.rx_bytes >= 0) - vshPrint(ctl, "%s rx_bytes %lld\n", device, stats.rx_bytes); - - if (stats.rx_packets >= 0) - vshPrint(ctl, "%s rx_packets %lld\n", device, stats.rx_packets); - - if (stats.rx_errs >= 0) - vshPrint(ctl, "%s rx_errs %lld\n", device, stats.rx_errs); - - if (stats.rx_drop >= 0) - vshPrint(ctl, "%s rx_drop %lld\n", device, stats.rx_drop); - - if (stats.tx_bytes >= 0) - vshPrint(ctl, "%s tx_bytes %lld\n", device, stats.tx_bytes); - - if (stats.tx_packets >= 0) - vshPrint(ctl, "%s tx_packets %lld\n", device, stats.tx_packets); - - if (stats.tx_errs >= 0) - vshPrint(ctl, "%s tx_errs %lld\n", device, stats.tx_errs); - - if (stats.tx_drop >= 0) - vshPrint(ctl, "%s tx_drop %lld\n", device, stats.tx_drop); - - virDomainFree(dom); - return true; -} - -/* "domif-setlink" command - */ -static const vshCmdInfo info_domif_setlink[] = { - {"help", N_("set link state of a virtual interface")}, - {"desc", N_("Set link state of a domain's virtual interface. This command wraps usage of update-device command.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domif_setlink[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, - {"state", VSH_OT_DATA, VSH_OFLAG_REQ, N_("new state of the device")}, - {"persistent", VSH_OT_ALIAS, 0, "config"}, - {"config", VSH_OT_BOOL, 0, N_("affect next boot")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomIfSetLink(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *iface; - const char *state; - const char *value; - const char *desc; - virMacAddr macaddr; - const char *element; - const char *attr; - bool config; - bool ret = false; - unsigned int flags = 0; - int i; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlXPathObjectPtr obj = NULL; - xmlNodePtr cur = NULL; - xmlBufferPtr xml_buf = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if (vshCommandOptString(cmd, "interface", &iface) <= 0) - goto cleanup; - - if (vshCommandOptString(cmd, "state", &state) <= 0) - goto cleanup; - - config = vshCommandOptBool(cmd, "config"); - - if (STRNEQ(state, "up") && STRNEQ(state, "down")) { - vshError(ctl, _("invalid link state '%s'"), state); - goto cleanup; - } - - /* get persistent or live description of network device */ - desc = virDomainGetXMLDesc(dom, config ? VIR_DOMAIN_XML_INACTIVE : 0); - if (desc == NULL) { - vshError(ctl, _("Failed to get domain description xml")); - goto cleanup; - } - - if (config) - flags = VIR_DOMAIN_AFFECT_CONFIG; - else - flags = VIR_DOMAIN_AFFECT_LIVE; - - if (virDomainIsActive(dom) == 0) - flags = VIR_DOMAIN_AFFECT_CONFIG; + if (virDomainIsActive(dom) == 0) + flags = VIR_DOMAIN_AFFECT_CONFIG; /* extract current network device description */ xml = virXMLParseStringCtxt(desc, _("(domain_definition)"), &ctxt); @@ -2050,166 +1272,37 @@ hit: BAD_CAST "link", NULL); if (!cur) - goto cleanup; - - if (xmlNewProp(cur, BAD_CAST "state", BAD_CAST state) == NULL) - goto cleanup; - } - - xml_buf = xmlBufferCreate(); - if (!xml_buf) { - vshError(ctl, _("Failed to allocate memory")); - goto cleanup; - } - - if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0 ) { - vshError(ctl, _("Failed to create XML")); - goto cleanup; - } - - if (virDomainUpdateDeviceFlags(dom, (char *)xmlBufferContent(xml_buf), flags) < 0) { - vshError(ctl, _("Failed to update interface link state")); - goto cleanup; - } else { - vshPrint(ctl, "%s", _("Device updated successfully\n")); - ret = true; - } - -cleanup: - xmlXPathFreeObject(obj); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(xml); - xmlBufferFree(xml_buf); - - if (dom) - virDomainFree(dom); - - return ret; -} - -/* "domif-getlink" command - */ -static const vshCmdInfo info_domif_getlink[] = { - {"help", N_("get link state of a virtual interface")}, - {"desc", N_("Get link state of a domain's virtual interface.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_domif_getlink[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, N_("interface device (MAC Address)")}, - {"persistent", VSH_OT_ALIAS, 0, "config"}, - {"config", VSH_OT_BOOL, 0, N_("Get persistent interface state")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomIfGetLink(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *iface = NULL; - int flags = 0; - char *state = NULL; - char *value = NULL; - virMacAddr macaddr; - const char *element; - const char *attr; - bool ret = false; - int i; - char *desc; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr cur = NULL; - xmlXPathObjectPtr obj = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if (vshCommandOptString(cmd, "interface", &iface) <= 0) { - virDomainFree(dom); - return false; - } - - if (vshCommandOptBool(cmd, "config")) - flags = VIR_DOMAIN_XML_INACTIVE; - - desc = virDomainGetXMLDesc(dom, flags); - if (desc == NULL) { - vshError(ctl, _("Failed to get domain description xml")); - goto cleanup; - } - - xml = virXMLParseStringCtxt(desc, _("(domain_definition)"), &ctxt); - VIR_FREE(desc); - if (!xml) { - vshError(ctl, _("Failed to parse domain description xml")); - goto cleanup; - } - - obj = xmlXPathEval(BAD_CAST "/domain/devices/interface", ctxt); - if (obj == NULL || obj->type != XPATH_NODESET || - obj->nodesetval == NULL || obj->nodesetval->nodeNr == 0) { - vshError(ctl, _("Failed to extract interface information or no interfaces found")); - goto cleanup; - } - - if (virMacAddrParse(iface, &macaddr) == 0) { - element = "mac"; - attr = "address"; - } else { - element = "target"; - attr = "dev"; - } - - /* find interface with matching mac addr */ - for (i = 0; i < obj->nodesetval->nodeNr; i++) { - cur = obj->nodesetval->nodeTab[i]->children; - - while (cur) { - if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST element)) { - - value = virXMLPropString(cur, attr); - - if (STRCASEEQ(value, iface)) { - VIR_FREE(value); - goto hit; - } - VIR_FREE(value); - } - cur = cur->next; - } - } - - vshError(ctl, _("Interface (%s: %s) not found."), element, iface); - goto cleanup; - -hit: - cur = obj->nodesetval->nodeTab[i]->children; - while (cur) { - if (cur->type == XML_ELEMENT_NODE && - xmlStrEqual(cur->name, BAD_CAST "link")) { - - state = virXMLPropString(cur, "state"); - vshPrint(ctl, "%s %s", iface, state); - VIR_FREE(state); + goto cleanup; + if (xmlNewProp(cur, BAD_CAST "state", BAD_CAST state) == NULL) goto cleanup; - } - cur = cur->next; } - /* attribute not found */ - vshPrint(ctl, "%s default", iface); + xml_buf = xmlBufferCreate(); + if (!xml_buf) { + vshError(ctl, _("Failed to allocate memory")); + goto cleanup; + } + + if (xmlNodeDump(xml_buf, xml, obj->nodesetval->nodeTab[i], 0, 0) < 0 ) { + vshError(ctl, _("Failed to create XML")); + goto cleanup; + } + + if (virDomainUpdateDeviceFlags(dom, (char *)xmlBufferContent(xml_buf), flags) < 0) { + vshError(ctl, _("Failed to update interface link state")); + goto cleanup; + } else { + vshPrint(ctl, "%s", _("Device updated successfully\n")); + ret = true; + } - ret = true; cleanup: xmlXPathFreeObject(obj); xmlXPathFreeContext(ctxt); xmlFreeDoc(xml); + xmlBufferFree(xml_buf); + if (dom) virDomainFree(dom); @@ -2345,381 +1438,69 @@ cmdDomIftune(vshControl *ctl, const vshCmd *cmd) /* set the interface parameters */ params = vshCalloc(ctl, nparams, sizeof(*params)); if (!params) { - virReportOOMError(); - goto cleanup; - } - - for (i = 0; i < nparams; i++) - params[i].type = VIR_TYPED_PARAM_UINT; - - i = 0; - if (inbound.average && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = inbound.average; - i++; - } - if (inbound.peak && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_PEAK, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = inbound.peak; - i++; - } - if (inbound.burst && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_BURST, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = inbound.burst; - i++; - } - if (outbound.average && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = outbound.average; - i++; - } - if (outbound.peak && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = outbound.peak; - i++; - } - if (outbound.burst && i < nparams) { - if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_BURST, - sizeof(params[i].field))) - goto cleanup; - params[i].value.ui = outbound.burst; - i++; - } - - if (virDomainSetInterfaceParameters(dom, device, params, nparams, flags) != 0) { - vshError(ctl, "%s", _("Unable to set interface parameters")); - goto cleanup; - } - } - - ret = true; - -cleanup: - virTypedParameterArrayClear(params, nparams); - VIR_FREE(params); - virDomainFree(dom); - return ret; -} - -/* - * "dommemstats" command - */ -static const vshCmdInfo info_dommemstat[] = { - {"help", N_("get memory statistics for a domain")}, - {"desc", N_("Get memory statistics for a running domain.")}, - {NULL,NULL} -}; - -static const vshCmdOptDef opts_dommemstat[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomMemStat(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - const char *name; - struct _virDomainMemoryStat stats[VIR_DOMAIN_MEMORY_STAT_NR]; - unsigned int nr_stats, i; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; - - 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); - virDomainFree(dom); - return false; - } - - 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); - } - - virDomainFree(dom); - return true; -} - -/* - * "domblkinfo" command - */ -static const vshCmdInfo info_domblkinfo[] = { - {"help", N_("domain block device size information")}, - {"desc", N_("Get block device size info for a domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domblkinfo[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomblkinfo(vshControl *ctl, const vshCmd *cmd) -{ - virDomainBlockInfo info; - virDomainPtr dom; - bool ret = true; - const char *device = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if (vshCommandOptString(cmd, "device", &device) <= 0) { - virDomainFree(dom); - return false; - } - - if (virDomainGetBlockInfo(dom, device, &info, 0) < 0) { - virDomainFree(dom); - return false; - } - - vshPrint(ctl, "%-15s %llu\n", _("Capacity:"), info.capacity); - vshPrint(ctl, "%-15s %llu\n", _("Allocation:"), info.allocation); - vshPrint(ctl, "%-15s %llu\n", _("Physical:"), info.physical); - - virDomainFree(dom); - return ret; -} - -/* - * "domblklist" command - */ -static const vshCmdInfo info_domblklist[] = { - {"help", N_("list all domain blocks")}, - {"desc", N_("Get the summary of block devices for a domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domblklist[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"inactive", VSH_OT_BOOL, 0, - N_("get inactive rather than running configuration")}, - {"details", VSH_OT_BOOL, 0, - N_("additionally display the type and device value")}, - {NULL, 0, 0, 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; - int i; - bool details = false; - - if (vshCommandOptBool(cmd, "inactive")) - flags |= VIR_DOMAIN_XML_INACTIVE; - - details = vshCommandOptBool(cmd, "details"); - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - 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) - vshPrint(ctl, "%-10s %-10s %-10s %s\n", _("Type"), - _("Device"), _("Target"), _("Source")); - else - vshPrint(ctl, "%-10s %s\n", _("Target"), _("Source")); - - vshPrint(ctl, "------------------------------------------------\n"); - - for (i = 0; i < ndisks; i++) { - char *type; - char *device; - char *target; - char *source; - - ctxt->node = disks[i]; - - if (details) { - type = virXPathString("string(./@type)", ctxt); - device = virXPathString("string(./@device)", ctxt); - } - - target = virXPathString("string(./target/@dev)", ctxt); - if (!target) { - vshError(ctl, "unable to query block list"); - 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")}, - {"desc", N_("Get the summary of virtual interfaces for a domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domiflist[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"inactive", VSH_OT_BOOL, 0, - N_("get inactive rather than running configuration")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomiflist(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - bool ret = false; - unsigned int flags = 0; - char *xml = NULL; - xmlDocPtr xmldoc = NULL; - xmlXPathContextPtr ctxt = NULL; - int ninterfaces; - xmlNodePtr *interfaces = NULL; - int i; - - if (vshCommandOptBool(cmd, "inactive")) - flags |= VIR_DOMAIN_XML_INACTIVE; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - 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; - - ninterfaces = virXPathNodeSet("./devices/interface", ctxt, &interfaces); - if (ninterfaces < 0) - goto cleanup; - - vshPrint(ctl, "%-10s %-10s %-10s %-11s %s\n", _("Interface"), _("Type"), - _("Source"), _("Model"), _("MAC")); - vshPrint(ctl, "-------------------------------------------------------\n"); - - for (i = 0; i < ninterfaces; i++) { - char *type = NULL; - char *source = NULL; - char *target = NULL; - char *model = NULL; - char *mac = NULL; - - ctxt->node = interfaces[i]; - type = virXPathString("string(./@type)", ctxt); - - source = virXPathString("string(./source/@bridge" - "|./source/@dev" - "|./source/@network" - "|./source/@name)", ctxt); + virReportOOMError(); + goto cleanup; + } - target = virXPathString("string(./target/@dev)", ctxt); - model = virXPathString("string(./model/@type)", ctxt); - mac = virXPathString("string(./mac/@address)", ctxt); + for (i = 0; i < nparams; i++) + params[i].type = VIR_TYPED_PARAM_UINT; - vshPrint(ctl, "%-10s %-10s %-10s %-11s %-10s\n", - target ? target : "-", - type, - source ? source : "-", - model ? model : "-", - mac ? mac : "-"); + i = 0; + if (inbound.average && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = inbound.average; + i++; + } + if (inbound.peak && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_PEAK, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = inbound.peak; + i++; + } + if (inbound.burst && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_IN_BURST, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = inbound.burst; + i++; + } + if (outbound.average && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = outbound.average; + i++; + } + if (outbound.peak && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = outbound.peak; + i++; + } + if (outbound.burst && i < nparams) { + if (!virStrcpy(params[i].field, VIR_DOMAIN_BANDWIDTH_OUT_BURST, + sizeof(params[i].field))) + goto cleanup; + params[i].value.ui = outbound.burst; + i++; + } - VIR_FREE(type); - VIR_FREE(source); - VIR_FREE(target); - VIR_FREE(model); - VIR_FREE(mac); + if (virDomainSetInterfaceParameters(dom, device, params, nparams, flags) != 0) { + vshError(ctl, "%s", _("Unable to set interface parameters")); + goto cleanup; + } } ret = true; cleanup: - VIR_FREE(interfaces); + virTypedParameterArrayClear(params, nparams); + VIR_FREE(params); virDomainFree(dom); - VIR_FREE(xml); - xmlFreeDoc(xmldoc); - xmlXPathFreeContext(ctxt); return ret; } @@ -4731,144 +3512,6 @@ cmdDestroy(vshControl *ctl, const vshCmd *cmd) } /* - * "dominfo" command - */ -static const vshCmdInfo info_dominfo[] = { - {"help", N_("domain information")}, - {"desc", N_("Returns basic information about the domain.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_dominfo[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDominfo(vshControl *ctl, const vshCmd *cmd) -{ - virDomainInfo info; - virDomainPtr dom; - virSecurityModel secmodel; - virSecurityLabelPtr seclabel; - int persistent = 0; - bool ret = true; - int autostart; - unsigned int id; - char *str, uuid[VIR_UUID_STRING_BUFLEN]; - int has_managed_save = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - id = virDomainGetID(dom); - if (id == ((unsigned int)-1)) - vshPrint(ctl, "%-15s %s\n", _("Id:"), "-"); - else - vshPrint(ctl, "%-15s %d\n", _("Id:"), id); - vshPrint(ctl, "%-15s %s\n", _("Name:"), virDomainGetName(dom)); - - if (virDomainGetUUIDString(dom, &uuid[0])==0) - vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); - - if ((str = virDomainGetOSType(dom))) { - vshPrint(ctl, "%-15s %s\n", _("OS Type:"), str); - VIR_FREE(str); - } - - if (virDomainGetInfo(dom, &info) == 0) { - vshPrint(ctl, "%-15s %s\n", _("State:"), - _(vshDomainStateToString(info.state))); - - vshPrint(ctl, "%-15s %d\n", _("CPU(s):"), info.nrVirtCpu); - - if (info.cpuTime != 0) { - double cpuUsed = info.cpuTime; - - cpuUsed /= 1000000000.0; - - vshPrint(ctl, "%-15s %.1lfs\n", _("CPU time:"), cpuUsed); - } - - if (info.maxMem != UINT_MAX) - vshPrint(ctl, "%-15s %lu KiB\n", _("Max memory:"), - info.maxMem); - else - vshPrint(ctl, "%-15s %s\n", _("Max memory:"), - _("no limit")); - - vshPrint(ctl, "%-15s %lu KiB\n", _("Used memory:"), - info.memory); - - } else { - ret = false; - } - - /* Check and display whether the domain is persistent or not */ - persistent = virDomainIsPersistent(dom); - vshDebug(ctl, VSH_ERR_DEBUG, "Domain persistent flag value: %d\n", - persistent); - if (persistent < 0) - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Persistent:"), persistent ? _("yes") : _("no")); - - /* Check and display whether the domain autostarts or not */ - if (!virDomainGetAutostart(dom, &autostart)) { - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), - autostart ? _("enable") : _("disable") ); - } - - has_managed_save = virDomainHasManagedSaveImage(dom, 0); - if (has_managed_save < 0) - vshPrint(ctl, "%-15s %s\n", _("Managed save:"), _("unknown")); - else - vshPrint(ctl, "%-15s %s\n", _("Managed save:"), - has_managed_save ? _("yes") : _("no")); - - /* Security model and label information */ - memset(&secmodel, 0, sizeof(secmodel)); - if (virNodeGetSecurityModel(ctl->conn, &secmodel) == -1) { - if (last_error->code != VIR_ERR_NO_SUPPORT) { - virDomainFree(dom); - return false; - } else { - virFreeError(last_error); - last_error = NULL; - } - } else { - /* Only print something if a security model is active */ - if (secmodel.model[0] != '\0') { - vshPrint(ctl, "%-15s %s\n", _("Security model:"), secmodel.model); - vshPrint(ctl, "%-15s %s\n", _("Security DOI:"), secmodel.doi); - - /* Security labels are only valid for active domains */ - if (VIR_ALLOC(seclabel) < 0) { - virDomainFree(dom); - return false; - } - - if (virDomainGetSecurityLabel(dom, seclabel) == -1) { - virDomainFree(dom); - VIR_FREE(seclabel); - return false; - } else { - if (seclabel->label[0] != '\0') - vshPrint(ctl, "%-15s %s (%s)\n", _("Security label:"), - seclabel->label, seclabel->enforcing ? "enforcing" : "permissive"); - } - - VIR_FREE(seclabel); - } - } - virDomainFree(dom); - return ret; -} - -/* * "domjobinfo" command */ static const vshCmdInfo info_domjobinfo[] = { @@ -17995,83 +16638,6 @@ cleanup: } /* - * "domblkerror" command - */ -static const char * -vshDomainIOErrorToString(int error) -{ - switch ((virDomainDiskErrorCode) error) { - case VIR_DOMAIN_DISK_ERROR_NONE: - return _("no error"); - case VIR_DOMAIN_DISK_ERROR_UNSPEC: - return _("unspecified error"); - case VIR_DOMAIN_DISK_ERROR_NO_SPACE: - return _("no space"); - case VIR_DOMAIN_DISK_ERROR_LAST: - ; - } - - return _("unknown error"); -} - -static const vshCmdInfo info_domblkerror[] = { - {"help", N_("Show errors on block devices")}, - {"desc", N_("Show block device errors")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_domblkerror[] = { - {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id, or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdDomBlkError(vshControl *ctl, const vshCmd *cmd) -{ - virDomainPtr dom; - virDomainDiskErrorPtr disks = NULL; - unsigned int ndisks; - int i; - int count; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if ((count = virDomainGetDiskErrors(dom, NULL, 0, 0)) < 0) - goto cleanup; - ndisks = count; - - if (ndisks) { - if (VIR_ALLOC_N(disks, ndisks) < 0) - goto cleanup; - - if ((count = virDomainGetDiskErrors(dom, disks, ndisks, 0)) == -1) - goto cleanup; - } - - if (count == 0) { - vshPrint(ctl, _("No errors found\n")); - } else { - for (i = 0; i < count; i++) { - vshPrint(ctl, "%s: %s\n", - disks[i].disk, - vshDomainIOErrorToString(disks[i].error)); - } - } - - ret = true; - -cleanup: - VIR_FREE(disks); - virDomainFree(dom); - return ret; -} - -/* * "qemu-monitor-command" command */ static const vshCmdInfo info_qemu_monitor_command[] = { @@ -19536,215 +18102,6 @@ vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason) return info.state; } -static const char * -vshDomainStateToString(int state) -{ - /* Can't use virDomainStateTypeToString, because we want to mark - * strings for translation. */ - switch ((virDomainState) state) { - case VIR_DOMAIN_RUNNING: - return N_("running"); - case VIR_DOMAIN_BLOCKED: - return N_("idle"); - case VIR_DOMAIN_PAUSED: - return N_("paused"); - case VIR_DOMAIN_SHUTDOWN: - return N_("in shutdown"); - case VIR_DOMAIN_SHUTOFF: - return N_("shut off"); - case VIR_DOMAIN_CRASHED: - return N_("crashed"); - case VIR_DOMAIN_PMSUSPENDED: - return N_("pmsuspended"); - case VIR_DOMAIN_NOSTATE: - default: - ;/*FALLTHROUGH*/ - } - return N_("no state"); /* = dom0 state */ -} - -static const char * -vshDomainStateReasonToString(int state, int reason) -{ - switch ((virDomainState) state) { - case VIR_DOMAIN_NOSTATE: - switch ((virDomainNostateReason) reason) { - case VIR_DOMAIN_NOSTATE_UNKNOWN: - case VIR_DOMAIN_NOSTATE_LAST: - ; - } - break; - - case VIR_DOMAIN_RUNNING: - switch ((virDomainRunningReason) reason) { - case VIR_DOMAIN_RUNNING_BOOTED: - return N_("booted"); - case VIR_DOMAIN_RUNNING_MIGRATED: - return N_("migrated"); - case VIR_DOMAIN_RUNNING_RESTORED: - return N_("restored"); - case VIR_DOMAIN_RUNNING_FROM_SNAPSHOT: - return N_("from snapshot"); - case VIR_DOMAIN_RUNNING_UNPAUSED: - return N_("unpaused"); - case VIR_DOMAIN_RUNNING_MIGRATION_CANCELED: - return N_("migration canceled"); - case VIR_DOMAIN_RUNNING_SAVE_CANCELED: - return N_("save canceled"); - case VIR_DOMAIN_RUNNING_WAKEUP: - return N_("event wakeup"); - case VIR_DOMAIN_RUNNING_UNKNOWN: - case VIR_DOMAIN_RUNNING_LAST: - ; - } - break; - - case VIR_DOMAIN_BLOCKED: - switch ((virDomainBlockedReason) reason) { - case VIR_DOMAIN_BLOCKED_UNKNOWN: - case VIR_DOMAIN_BLOCKED_LAST: - ; - } - break; - - case VIR_DOMAIN_PAUSED: - switch ((virDomainPausedReason) reason) { - case VIR_DOMAIN_PAUSED_USER: - return N_("user"); - case VIR_DOMAIN_PAUSED_MIGRATION: - return N_("migrating"); - case VIR_DOMAIN_PAUSED_SAVE: - return N_("saving"); - case VIR_DOMAIN_PAUSED_DUMP: - return N_("dumping"); - case VIR_DOMAIN_PAUSED_IOERROR: - return N_("I/O error"); - case VIR_DOMAIN_PAUSED_WATCHDOG: - return N_("watchdog"); - case VIR_DOMAIN_PAUSED_FROM_SNAPSHOT: - return N_("from snapshot"); - case VIR_DOMAIN_PAUSED_SHUTTING_DOWN: - return N_("shutting down"); - case VIR_DOMAIN_PAUSED_UNKNOWN: - case VIR_DOMAIN_PAUSED_LAST: - ; - } - break; - - case VIR_DOMAIN_SHUTDOWN: - switch ((virDomainShutdownReason) reason) { - case VIR_DOMAIN_SHUTDOWN_USER: - return N_("user"); - case VIR_DOMAIN_SHUTDOWN_UNKNOWN: - case VIR_DOMAIN_SHUTDOWN_LAST: - ; - } - break; - - case VIR_DOMAIN_SHUTOFF: - switch ((virDomainShutoffReason) reason) { - case VIR_DOMAIN_SHUTOFF_SHUTDOWN: - return N_("shutdown"); - case VIR_DOMAIN_SHUTOFF_DESTROYED: - return N_("destroyed"); - case VIR_DOMAIN_SHUTOFF_CRASHED: - return N_("crashed"); - case VIR_DOMAIN_SHUTOFF_MIGRATED: - return N_("migrated"); - case VIR_DOMAIN_SHUTOFF_SAVED: - return N_("saved"); - case VIR_DOMAIN_SHUTOFF_FAILED: - return N_("failed"); - case VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT: - return N_("from snapshot"); - case VIR_DOMAIN_SHUTOFF_UNKNOWN: - case VIR_DOMAIN_SHUTOFF_LAST: - ; - } - break; - - case VIR_DOMAIN_CRASHED: - switch ((virDomainCrashedReason) reason) { - case VIR_DOMAIN_CRASHED_UNKNOWN: - case VIR_DOMAIN_CRASHED_LAST: - ; - } - break; - - case VIR_DOMAIN_PMSUSPENDED: - switch ((virDomainPMSuspendedReason) reason) { - case VIR_DOMAIN_PMSUSPENDED_UNKNOWN: - case VIR_DOMAIN_PMSUSPENDED_LAST: - ; - } - break; - - case VIR_DOMAIN_LAST: - ; - } - - return N_("unknown"); -} - -/* extract description or title from domain xml */ -static 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, ""); - virResetLastError(); - 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; -} - /* Return a non-NULL string representation of a typed parameter; exit * if we are out of memory. */ static char * @@ -19814,25 +18171,6 @@ vshFindTypedParamByName(const char *name, virTypedParameterPtr list, int count) } static const char * -vshDomainControlStateToString(int state) -{ - switch ((virDomainControlState) state) { - case VIR_DOMAIN_CONTROL_OK: - return N_("ok"); - case VIR_DOMAIN_CONTROL_JOB: - return N_("background job"); - case VIR_DOMAIN_CONTROL_OCCUPIED: - return N_("occupied"); - case VIR_DOMAIN_CONTROL_ERROR: - return N_("error"); - default: - ; - } - - return N_("unknown"); -} - -static const char * vshDomainVcpuStateToString(int state) { switch (state) { @@ -20815,6 +19153,8 @@ static const vshCmdDef domManagementCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-domain-monitor.c" + static const vshCmdDef domMonitoringCmds[] = { {"domblkerror", cmdDomBlkError, opts_domblkerror, info_domblkerror, 0}, {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo, 0}, -- 1.7.7.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list