diff --git a/cfg.mk b/cfg.mk index 47d2ea818bb4882033ade2f11ae13adaefb6c716..ce5ea9a65bb0f0aaa3e0e3204a311cd3a1806b85 100644 --- a/cfg.mk +++ b/cfg.mk @@ -773,7 +773,7 @@ exclude_file_name_regexp--sc_prohibit_xmlURI = ^src/util/viruri\.c$$ exclude_file_name_regexp--sc_prohibit_return_as_function = \.py$$ -_virsh_includes=(edit|domain-monitor|domain) +_virsh_includes=(edit|domain-monitor|domain|volume) exclude_file_name_regexp--sc_require_config_h = ^(examples/|tools/virsh-$(_virsh_includes)\.c$$) exclude_file_name_regexp--sc_require_config_h_first = ^(examples/|tools/virsh-$(_virsh_includes)\.c$$) diff --git a/po/POTFILES.in b/po/POTFILES.in index fb9891dc0127d20d777cae27052775b628426b70..718304f763f138ac60b29e5c6d0b4d648edf128c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -180,6 +180,7 @@ tools/virsh.c tools/virsh-domain-monitor.c tools/virsh-domain.c tools/virsh-edit.c +tools/virsh-volume.c tools/virt-host-validate-common.c tools/virt-host-validate-lxc.c tools/virt-host-validate-qemu.c diff --git a/tools/virsh-volume.c b/tools/virsh-volume.c new file mode 100644 index 0000000000000000000000000000000000000000..88a42d9a57f14bb58123e5fa355bb523a15ea54b --- /dev/null +++ b/tools/virsh-volume.c @@ -0,0 +1,1440 @@ +/* + * virsh-volume.c: Commands to manage storage volume + * + * 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 + * . + * + * Daniel Veillard + * Karel Zak + * Daniel P. Berrange + * + */ + +/* default is lookup by Name and UUID */ +#define vshCommandOptVol(_ctl, _cmd, _optname, _pooloptname, _name) \ + vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ + VSH_BYUUID|VSH_BYNAME) + +static virStorageVolPtr +vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, + const char *optname, + const char *pooloptname, + const char **name, int flag) +{ + virStorageVolPtr vol = NULL; + virStoragePoolPtr pool = NULL; + const char *n = NULL, *p = NULL; + + if (vshCommandOptString(cmd, optname, &n) <= 0) + return NULL; + + if (pooloptname != NULL && vshCommandOptString(cmd, pooloptname, &p) < 0) { + vshError(ctl, "%s", _("missing option")); + return NULL; + } + + if (p) + pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag); + + vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n", + cmd->def->name, optname, n); + + if (name) + *name = n; + + /* try it by name */ + if (pool && (flag & VSH_BYNAME)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n", + cmd->def->name, optname); + vol = virStorageVolLookupByName(pool, n); + } + /* try it by key */ + if (vol == NULL && (flag & VSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n", + cmd->def->name, optname); + vol = virStorageVolLookupByKey(ctl->conn, n); + } + /* try it by path */ + if (vol == NULL && (flag & VSH_BYUUID)) { + vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n", + cmd->def->name, optname); + vol = virStorageVolLookupByPath(ctl->conn, n); + } + + if (!vol) { + if (pool) + vshError(ctl, _("failed to get vol '%s'"), n); + else + vshError(ctl, _("failed to get vol '%s', specifying --%s " + "might help"), n, pooloptname); + } + + if (pool) + virStoragePoolFree(pool); + + return vol; +} + +/* + * "vol-create-as" command + */ +static const vshCmdInfo info_vol_create_as[] = { + {"help", N_("create a volume from a set of args")}, + {"desc", N_("Create a vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create_as[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, + {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")}, + {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("size of the vol, as scaled integer (default bytes)")}, + {"allocation", VSH_OT_STRING, 0, + N_("initial allocation size, as scaled integer (default bytes)")}, + {"format", VSH_OT_STRING, 0, + N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")}, + {"backing-vol", VSH_OT_STRING, 0, + N_("the backing volume if taking a snapshot")}, + {"backing-vol-format", VSH_OT_STRING, 0, + N_("format of backing volume if taking a snapshot")}, + {NULL, 0, 0, NULL} +}; + +static int +vshVolSize(const char *data, unsigned long long *val) +{ + char *end; + if (virStrToLong_ull(data, &end, 10, val) < 0) + return -1; + return virScaleInteger(val, end, 1, ULLONG_MAX); +} + +static bool +cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char *xml; + const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL; + const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL; + unsigned long long capacity, allocation = 0; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return false; + + if (vshCommandOptString(cmd, "name", &name) <= 0) + goto cleanup; + + if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) + goto cleanup; + + if (vshVolSize(capacityStr, &capacity) < 0) { + vshError(ctl, _("Malformed size %s"), capacityStr); + goto cleanup; + } + + if (vshCommandOptString(cmd, "allocation", &allocationStr) > 0 && + vshVolSize(allocationStr, &allocation) < 0) { + vshError(ctl, _("Malformed size %s"), allocationStr); + goto cleanup; + } + + if (vshCommandOptString(cmd, "format", &format) < 0 || + vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 || + vshCommandOptString(cmd, "backing-vol-format", + &snapshotStrFormat) < 0) { + vshError(ctl, "%s", _("missing argument")); + goto cleanup; + } + + + virBufferAddLit(&buf, "\n"); + virBufferAsprintf(&buf, " %s\n", name); + virBufferAsprintf(&buf, " %llu\n", capacity); + if (allocationStr) + virBufferAsprintf(&buf, " %llu\n", allocation); + + if (format) { + virBufferAddLit(&buf, " \n"); + virBufferAsprintf(&buf, " \n",format); + virBufferAddLit(&buf, " \n"); + } + + /* Convert the snapshot parameters into backingStore XML */ + if (snapshotStrVol) { + /* Lookup snapshot backing volume. Try the backing-vol + * parameter as a name */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as name\n", + cmd->def->name, snapshotStrVol); + virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as name\n", + cmd->def->name, snapshotStrVol); + + if (snapVol == NULL) { + /* Snapshot backing volume not found by name. Try the + * backing-vol parameter as a key */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as key\n", + cmd->def->name, snapshotStrVol); + snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as key\n", + cmd->def->name, snapshotStrVol); + } + if (snapVol == NULL) { + /* Snapshot backing volume not found by key. Try the + * backing-vol parameter as a path */ + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Look up backing store volume '%s' as path\n", + cmd->def->name, snapshotStrVol); + snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol); + if (snapVol) + vshDebug(ctl, VSH_ERR_DEBUG, + "%s: Backing store volume found using '%s' as path\n", + cmd->def->name, snapshotStrVol); + } + if (snapVol == NULL) { + vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol); + goto cleanup; + } + + char *snapshotStrVolPath; + if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) { + virStorageVolFree(snapVol); + goto cleanup; + } + + /* Create XML for the backing store */ + virBufferAddLit(&buf, " \n"); + virBufferAsprintf(&buf, " %s\n",snapshotStrVolPath); + if (snapshotStrFormat) + virBufferAsprintf(&buf, " \n",snapshotStrFormat); + virBufferAddLit(&buf, " \n"); + + /* Cleanup snapshot allocations */ + VIR_FREE(snapshotStrVolPath); + virStorageVolFree(snapVol); + } + + virBufferAddLit(&buf, "\n"); + + if (virBufferError(&buf)) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + xml = virBufferContentAndReset(&buf); + vol = virStorageVolCreateXML(pool, xml, 0); + VIR_FREE(xml); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created\n"), name); + virStorageVolFree(vol); + return true; + } else { + vshError(ctl, _("Failed to create vol %s"), name); + return false; + } + + cleanup: + virBufferFreeAndReset(&buf); + virStoragePoolFree(pool); + return false; +} + +/* + * "vol-create" command + */ +static const vshCmdInfo info_vol_create[] = { + {"help", N_("create a vol from an XML file")}, + {"desc", N_("Create a vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolCreate(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + const char *from = NULL; + bool ret = true; + char *buffer; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) + return false; + + if (vshCommandOptString(cmd, "file", &from) <= 0) { + virStoragePoolFree(pool); + return false; + } + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { + virshReportError(ctl); + virStoragePoolFree(pool); + return false; + } + + vol = virStorageVolCreateXML(pool, buffer, 0); + VIR_FREE(buffer); + virStoragePoolFree(pool); + + if (vol != NULL) { + vshPrint(ctl, _("Vol %s created from %s\n"), + virStorageVolGetName(vol), from); + virStorageVolFree(vol); + } else { + vshError(ctl, _("Failed to create vol from %s"), from); + ret = false; + } + return ret; +} + +/* + * "vol-create-from" command + */ +static const vshCmdInfo info_vol_create_from[] = { + {"help", N_("create a vol, using another volume as input")}, + {"desc", N_("Create a vol from an existing volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_create_from[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")}, + {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool = NULL; + virStorageVolPtr newvol = NULL, inputvol = NULL; + const char *from = NULL; + bool ret = false; + char *buffer = NULL; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + goto cleanup; + + if (vshCommandOptString(cmd, "file", &from) <= 0) { + goto cleanup; + } + + if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL))) + goto cleanup; + + if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { + virshReportError(ctl); + goto cleanup; + } + + newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0); + + if (newvol != NULL) { + vshPrint(ctl, _("Vol %s created from input vol %s\n"), + virStorageVolGetName(newvol), virStorageVolGetName(inputvol)); + } else { + vshError(ctl, _("Failed to create vol from %s"), from); + goto cleanup; + } + + ret = true; +cleanup: + VIR_FREE(buffer); + if (pool) + virStoragePoolFree(pool); + if (inputvol) + virStorageVolFree(inputvol); + if (newvol) + virStorageVolFree(newvol); + return ret; +} + +static xmlChar * +makeCloneXML(const char *origxml, const char *newname) +{ + + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlXPathObjectPtr obj = NULL; + xmlChar *newxml = NULL; + int size; + + doc = virXMLParseStringCtxt(origxml, _("(volume_definition)"), &ctxt); + if (!doc) + goto cleanup; + + obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt); + if (obj == NULL || obj->nodesetval == NULL || + obj->nodesetval->nodeTab == NULL) + goto cleanup; + + xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname); + xmlDocDumpMemory(doc, &newxml, &size); + +cleanup: + xmlXPathFreeObject(obj); + xmlXPathFreeContext(ctxt); + xmlFreeDoc(doc); + return newxml; +} + +/* + * "vol-clone" command + */ +static const vshCmdInfo info_vol_clone[] = { + {"help", N_("clone a volume.")}, + {"desc", N_("Clone an existing volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_clone[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")}, + {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolClone(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr origpool = NULL; + virStorageVolPtr origvol = NULL, newvol = NULL; + const char *name = NULL; + char *origxml = NULL; + xmlChar *newxml = NULL; + bool ret = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + goto cleanup; + + origpool = virStoragePoolLookupByVolume(origvol); + if (!origpool) { + vshError(ctl, "%s", _("failed to get parent pool")); + goto cleanup; + } + + if (vshCommandOptString(cmd, "newname", &name) <= 0) + goto cleanup; + + origxml = virStorageVolGetXMLDesc(origvol, 0); + if (!origxml) + goto cleanup; + + newxml = makeCloneXML(origxml, name); + if (!newxml) { + vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); + goto cleanup; + } + + newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0); + + if (newvol != NULL) { + vshPrint(ctl, _("Vol %s cloned from %s\n"), + virStorageVolGetName(newvol), virStorageVolGetName(origvol)); + } else { + vshError(ctl, _("Failed to clone vol from %s"), + virStorageVolGetName(origvol)); + goto cleanup; + } + + ret = true; + +cleanup: + VIR_FREE(origxml); + xmlFree(newxml); + if (origvol) + virStorageVolFree(origvol); + if (newvol) + virStorageVolFree(newvol); + if (origpool) + virStoragePoolFree(origpool); + return ret; +} + +/* + * "vol-upload" command + */ +static const vshCmdInfo info_vol_upload[] = { + {"help", N_("upload a file into a volume")}, + {"desc", N_("Upload a file into a volume")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_upload[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"offset", VSH_OT_INT, 0, N_("volume offset to upload to") }, + {"length", VSH_OT_INT, 0, N_("amount of data to upload") }, + {NULL, 0, 0, NULL} +}; + +static int +cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED, + char *bytes, size_t nbytes, void *opaque) +{ + int *fd = opaque; + + return saferead(*fd, bytes, nbytes); +} + +static bool +cmdVolUpload(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + virStorageVolPtr vol = NULL; + bool ret = false; + int fd = -1; + virStreamPtr st = NULL; + const char *name = NULL; + unsigned long long offset = 0, length = 0; + + if (!vshConnectionUsability(ctl, ctl->conn)) + goto cleanup; + + if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (vshCommandOptULongLong(cmd, "length", &length) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (vshCommandOptString(cmd, "file", &file) < 0) { + vshError(ctl, _("file must not be empty")); + goto cleanup; + } + + if ((fd = open(file, O_RDONLY)) < 0) { + vshError(ctl, _("cannot read %s"), file); + goto cleanup; + } + + st = virStreamNew(ctl->conn, 0); + if (virStorageVolUpload(vol, st, offset, length, 0) < 0) { + vshError(ctl, _("cannot upload to volume %s"), name); + goto cleanup; + } + + if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) { + vshError(ctl, _("cannot send data to volume %s"), name); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + vshError(ctl, _("cannot close file %s"), file); + virStreamAbort(st); + goto cleanup; + } + + if (virStreamFinish(st) < 0) { + vshError(ctl, _("cannot close volume %s"), name); + goto cleanup; + } + + ret = true; + +cleanup: + if (vol) + virStorageVolFree(vol); + if (st) + virStreamFree(st); + VIR_FORCE_CLOSE(fd); + return ret; +} + +/* + * "vol-download" command + */ +static const vshCmdInfo info_vol_download[] = { + {"help", N_("Download a volume to a file")}, + {"desc", N_("Download a volume to a file")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_download[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"offset", VSH_OT_INT, 0, N_("volume offset to download from") }, + {"length", VSH_OT_INT, 0, N_("amount of data to download") }, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDownload(vshControl *ctl, const vshCmd *cmd) +{ + const char *file = NULL; + virStorageVolPtr vol = NULL; + bool ret = false; + int fd = -1; + virStreamPtr st = NULL; + const char *name = NULL; + unsigned long long offset = 0, length = 0; + bool created = false; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (vshCommandOptULongLong(cmd, "length", &length) < 0) { + vshError(ctl, _("Unable to parse integer")); + return false; + } + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) + return false; + + if (vshCommandOptString(cmd, "file", &file) < 0) { + vshError(ctl, _("file must not be empty")); + goto cleanup; + } + + if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) { + if (errno != EEXIST || + (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) { + vshError(ctl, _("cannot create %s"), file); + goto cleanup; + } + } else { + created = true; + } + + st = virStreamNew(ctl->conn, 0); + if (virStorageVolDownload(vol, st, offset, length, 0) < 0) { + vshError(ctl, _("cannot download from volume %s"), name); + goto cleanup; + } + + if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) { + vshError(ctl, _("cannot receive data from volume %s"), name); + goto cleanup; + } + + if (VIR_CLOSE(fd) < 0) { + vshError(ctl, _("cannot close file %s"), file); + virStreamAbort(st); + goto cleanup; + } + + if (virStreamFinish(st) < 0) { + vshError(ctl, _("cannot close volume %s"), name); + goto cleanup; + } + + ret = true; + +cleanup: + VIR_FORCE_CLOSE(fd); + if (!ret && created) + unlink(file); + if (vol) + virStorageVolFree(vol); + if (st) + virStreamFree(st); + return ret; +} + +/* + * "vol-delete" command + */ +static const vshCmdInfo info_vol_delete[] = { + {"help", N_("delete a vol")}, + {"desc", N_("Delete a given vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_delete[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDelete(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = true; + const char *name; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (virStorageVolDelete(vol, 0) == 0) { + vshPrint(ctl, _("Vol %s deleted\n"), name); + } else { + vshError(ctl, _("Failed to delete vol %s"), name); + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-wipe" command + */ +static const vshCmdInfo info_vol_wipe[] = { + {"help", N_("wipe a vol")}, + {"desc", N_("Ensure data previously on a volume is not accessible to future reads")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_wipe[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"algorithm", VSH_OT_STRING, 0, N_("perform selected wiping algorithm")}, + {NULL, 0, 0, NULL} +}; + +VIR_ENUM_DECL(virStorageVolWipeAlgorithm) +VIR_ENUM_IMPL(virStorageVolWipeAlgorithm, VIR_STORAGE_VOL_WIPE_ALG_LAST, + "zero", "nnsa", "dod", "bsi", "gutmann", "schneier", + "pfitzner7", "pfitzner33", "random"); + +static bool +cmdVolWipe(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = false; + const char *name; + const char *algorithm_str = NULL; + int algorithm = VIR_STORAGE_VOL_WIPE_ALG_ZERO; + int funcRet; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { + return false; + } + + if (vshCommandOptString(cmd, "algorithm", &algorithm_str) < 0) { + vshError(ctl, "%s", _("missing argument")); + goto out; + } + + if (algorithm_str && + (algorithm = virStorageVolWipeAlgorithmTypeFromString(algorithm_str)) < 0) { + vshError(ctl, _("Unsupported algorithm '%s'"), algorithm_str); + goto out; + } + + if ((funcRet = virStorageVolWipePattern(vol, algorithm, 0)) < 0) { + if (last_error->code == VIR_ERR_NO_SUPPORT && + algorithm == VIR_STORAGE_VOL_WIPE_ALG_ZERO) + funcRet = virStorageVolWipe(vol, 0); + } + + if (funcRet < 0) { + vshError(ctl, _("Failed to wipe vol %s"), name); + goto out; + } + + vshPrint(ctl, _("Vol %s wiped\n"), name); + ret = true; +out: + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-info" command + */ +static const vshCmdInfo info_vol_info[] = { + {"help", N_("storage vol information")}, + {"desc", N_("Returns basic information about the storage vol.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_info[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolInfo info; + virStorageVolPtr vol; + bool ret = true; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol)); + + if (virStorageVolGetInfo(vol, &info) == 0) { + double val; + const char *unit; + switch(info.type) { + case VIR_STORAGE_VOL_FILE: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("file")); + break; + + case VIR_STORAGE_VOL_BLOCK: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("block")); + break; + + case VIR_STORAGE_VOL_DIR: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir")); + break; + + case VIR_STORAGE_VOL_NETWORK: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network")); + break; + + default: + vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown")); + } + + val = prettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); + + val = prettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); + } else { + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-resize" command + */ +static const vshCmdInfo info_vol_resize[] = { + {"help", N_("resize a vol")}, + {"desc", N_("Resizes a storage volume.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_resize[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, + N_("new capacity for the vol, as scaled integer (default bytes)")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {"allocate", VSH_OT_BOOL, 0, + N_("allocate the new capacity, rather than leaving it sparse")}, + {"delta", VSH_OT_BOOL, 0, + N_("use capacity as a delta to current size, rather than the new size")}, + {"shrink", VSH_OT_BOOL, 0, N_("allow the resize to shrink the volume")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolResize(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + const char *capacityStr = NULL; + unsigned long long capacity = 0; + unsigned int flags = 0; + bool ret = false; + bool delta = false; + + if (vshCommandOptBool(cmd, "allocate")) + flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE; + if (vshCommandOptBool(cmd, "delta")) { + delta = true; + flags |= VIR_STORAGE_VOL_RESIZE_DELTA; + } + if (vshCommandOptBool(cmd, "shrink")) + flags |= VIR_STORAGE_VOL_RESIZE_SHRINK; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) + goto cleanup; + virSkipSpaces(&capacityStr); + if (*capacityStr == '-') { + /* The API always requires a positive value; but we allow a + * negative value for convenience. */ + if (delta && vshCommandOptBool(cmd, "shrink")){ + capacityStr++; + } else { + vshError(ctl, "%s", + _("negative size requires --delta and --shrink")); + goto cleanup; + } + } + if (vshVolSize(capacityStr, &capacity) < 0) { + vshError(ctl, _("Malformed size %s"), capacityStr); + goto cleanup; + } + + if (virStorageVolResize(vol, capacity, flags) == 0) { + vshPrint(ctl, + delta ? _("Size of volume '%s' successfully changed by %s\n") + : _("Size of volume '%s' successfully changed to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = true; + } else { + vshError(ctl, + delta ? _("Failed to change size of volume '%s' by %s\n") + : _("Failed to change size of volume '%s' to %s\n"), + virStorageVolGetName(vol), capacityStr); + ret = false; + } + +cleanup: + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-dumpxml" command + */ +static const vshCmdInfo info_vol_dumpxml[] = { + {"help", N_("vol information in XML")}, + {"desc", N_("Output the vol information as an XML dump to stdout.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_dumpxml[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + bool ret = true; + char *dump; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + dump = virStorageVolGetXMLDesc(vol, 0); + if (dump != NULL) { + vshPrint(ctl, "%s", dump); + VIR_FREE(dump); + } else { + ret = false; + } + + virStorageVolFree(vol); + return ret; +} + +/* + * "vol-list" command + */ +static const vshCmdInfo info_vol_list[] = { + {"help", N_("list vols")}, + {"desc", N_("Returns list of vols by pool.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_list[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) +{ + virStorageVolInfo volumeInfo; + virStoragePoolPtr pool; + char **activeNames = NULL; + char *outputStr = NULL; + const char *unit; + double val; + bool details = vshCommandOptBool(cmd, "details"); + int numVolumes = 0, i; + int ret; + bool functionReturn; + int stringLength = 0; + size_t allocStrLength = 0, capStrLength = 0; + size_t nameStrLength = 0, pathStrLength = 0; + size_t typeStrLength = 0; + struct volInfoText { + char *allocation; + char *capacity; + char *path; + char *type; + }; + struct volInfoText *volInfoTexts = NULL; + + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + /* Look up the pool information given to us by the user */ + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false; + + /* Determine the number of volumes in the pool */ + numVolumes = virStoragePoolNumOfVolumes(pool); + + if (numVolumes < 0) { + vshError(ctl, "%s", _("Failed to list storage volumes")); + virStoragePoolFree(pool); + return false; + } + + /* Retrieve the list of volume names in the pool */ + if (numVolumes > 0) { + activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames)); + if ((numVolumes = virStoragePoolListVolumes(pool, activeNames, + numVolumes)) < 0) { + vshError(ctl, "%s", _("Failed to list active vols")); + VIR_FREE(activeNames); + virStoragePoolFree(pool); + return false; + } + + /* Sort the volume names */ + qsort(&activeNames[0], numVolumes, sizeof(*activeNames), vshNameSorter); + + /* Set aside memory for volume information pointers */ + volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts)); + } + + /* Collect the rest of the volume information for display */ + for (i = 0; i < numVolumes; i++) { + /* Retrieve volume info */ + virStorageVolPtr vol = virStorageVolLookupByName(pool, + activeNames[i]); + + /* Retrieve the volume path */ + if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) { + /* Something went wrong retrieving a volume path, cope with it */ + volInfoTexts[i].path = vshStrdup(ctl, _("unknown")); + } + + /* If requested, retrieve volume type and sizing information */ + if (details) { + if (virStorageVolGetInfo(vol, &volumeInfo) != 0) { + /* Something went wrong retrieving volume info, cope with it */ + volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); + volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); + volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); + } else { + /* Convert the returned volume info into output strings */ + + /* Volume type */ + switch (volumeInfo.type) { + case VIR_STORAGE_VOL_FILE: + volInfoTexts[i].type = vshStrdup(ctl, _("file")); + break; + case VIR_STORAGE_VOL_BLOCK: + volInfoTexts[i].type = vshStrdup(ctl, _("block")); + break; + case VIR_STORAGE_VOL_DIR: + volInfoTexts[i].type = vshStrdup(ctl, _("dir")); + break; + default: + volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); + } + + /* Create the capacity output string */ + val = prettyCapacity(volumeInfo.capacity, &unit); + ret = virAsprintf(&volInfoTexts[i].capacity, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Create the allocation output string */ + val = prettyCapacity(volumeInfo.allocation, &unit); + ret = virAsprintf(&volInfoTexts[i].allocation, + "%.2lf %s", val, unit); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + } + + /* Remember the largest length for each output string. + * This lets us displaying header and volume information rows + * using a single, properly sized, printf style output string. + */ + + /* Keep the length of name string if longest so far */ + stringLength = strlen(activeNames[i]); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Keep the length of path string if longest so far */ + stringLength = strlen(volInfoTexts[i].path); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Keep the length of type string if longest so far */ + stringLength = strlen(volInfoTexts[i].type); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Keep the length of capacity string if longest so far */ + stringLength = strlen(volInfoTexts[i].capacity); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Keep the length of allocation string if longest so far */ + stringLength = strlen(volInfoTexts[i].allocation); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + } + + /* Cleanup memory allocation */ + virStorageVolFree(vol); + } + + /* If the --details option wasn't selected, we output the volume + * info using the fixed string format from previous versions to + * maintain backward compatibility. + */ + + /* Output basic info then return if --details option not selected */ + if (!details) { + /* The old output format */ + vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path")); + vshPrintExtra(ctl, "-----------------------------------------\n"); + for (i = 0; i < numVolumes; i++) { + vshPrint(ctl, "%-20s %-40s\n", activeNames[i], + volInfoTexts[i].path); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + } + + /* We only get here if the --details option was selected. */ + + /* Use the length of name header string if it's longest */ + stringLength = strlen(_("Name")); + if (stringLength > nameStrLength) + nameStrLength = stringLength; + + /* Use the length of path header string if it's longest */ + stringLength = strlen(_("Path")); + if (stringLength > pathStrLength) + pathStrLength = stringLength; + + /* Use the length of type header string if it's longest */ + stringLength = strlen(_("Type")); + if (stringLength > typeStrLength) + typeStrLength = stringLength; + + /* Use the length of capacity header string if it's longest */ + stringLength = strlen(_("Capacity")); + if (stringLength > capStrLength) + capStrLength = stringLength; + + /* Use the length of allocation header string if it's longest */ + stringLength = strlen(_("Allocation")); + if (stringLength > allocStrLength) + allocStrLength = stringLength; + + /* Display the string lengths for debugging */ + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest name string = %zu chars\n", nameStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest path string = %zu chars\n", pathStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest type string = %zu chars\n", typeStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest capacity string = %zu chars\n", capStrLength); + vshDebug(ctl, VSH_ERR_DEBUG, + "Longest allocation string = %zu chars\n", allocStrLength); + + /* Create the output template */ + ret = virAsprintf(&outputStr, + "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n", + (unsigned long) nameStrLength, + (unsigned long) pathStrLength, + (unsigned long) typeStrLength, + (unsigned long) capStrLength, + (unsigned long) allocStrLength); + if (ret < 0) { + /* An error occurred creating the string, return */ + goto asprintf_failure; + } + + /* Display the header */ + vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"), + ("Capacity"), _("Allocation")); + for (i = nameStrLength + pathStrLength + typeStrLength + + capStrLength + allocStrLength + + 8; i > 0; i--) + vshPrintExtra(ctl, "-"); + vshPrintExtra(ctl, "\n"); + + /* Display the volume info rows */ + for (i = 0; i < numVolumes; i++) { + vshPrint(ctl, outputStr, + activeNames[i], + volInfoTexts[i].path, + volInfoTexts[i].type, + volInfoTexts[i].capacity, + volInfoTexts[i].allocation); + } + + /* Cleanup and return */ + functionReturn = true; + goto cleanup; + +asprintf_failure: + + /* Display an appropriate error message then cleanup and return */ + switch (errno) { + case ENOMEM: + /* Couldn't allocate memory */ + vshError(ctl, "%s", _("Out of memory")); + break; + default: + /* Some other error */ + vshError(ctl, _("virAsprintf failed (errno %d)"), errno); + } + functionReturn = false; + +cleanup: + + /* Safely free the memory allocated in this function */ + for (i = 0; i < numVolumes; i++) { + /* Cleanup the memory for one volume info structure per loop */ + VIR_FREE(volInfoTexts[i].path); + VIR_FREE(volInfoTexts[i].type); + VIR_FREE(volInfoTexts[i].capacity); + VIR_FREE(volInfoTexts[i].allocation); + VIR_FREE(activeNames[i]); + } + + /* Cleanup remaining memory */ + VIR_FREE(outputStr); + VIR_FREE(volInfoTexts); + VIR_FREE(activeNames); + virStoragePoolFree(pool); + + /* Return the desired value */ + return functionReturn; +} + +/* + * "vol-name" command + */ +static const vshCmdInfo info_vol_name[] = { + {"help", N_("returns the volume name for a given volume key or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_name[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolName(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, + VSH_BYUUID))) + return false; + + vshPrint(ctl, "%s\n", virStorageVolGetName(vol)); + virStorageVolFree(vol); + return true; +} + +/* + * "vol-pool" command + */ +static const vshCmdInfo info_vol_pool[] = { + {"help", N_("returns the storage pool for a given volume key or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_pool[] = { + {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")}, + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolPool(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolPtr pool; + virStorageVolPtr vol; + char uuid[VIR_UUID_STRING_BUFLEN]; + + /* Check the connection to libvirtd daemon is still working */ + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + /* Use the supplied string to locate the volume */ + if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, + VSH_BYUUID))) { + return false; + } + + /* Look up the parent storage pool for the volume */ + pool = virStoragePoolLookupByVolume(vol); + if (pool == NULL) { + vshError(ctl, "%s", _("failed to get parent pool")); + virStorageVolFree(vol); + return false; + } + + /* Return the requested details of the parent storage pool */ + if (vshCommandOptBool(cmd, "uuid")) { + /* Retrieve and return pool UUID string */ + if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0) + vshPrint(ctl, "%s\n", uuid); + } else { + /* Return the storage pool name */ + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + } + + /* Cleanup */ + virStorageVolFree(vol); + virStoragePoolFree(pool); + return true; +} + +/* + * "vol-key" command + */ +static const vshCmdInfo info_vol_key[] = { + {"help", N_("returns the volume key for a given volume name or path")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_key[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolKey(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + return false; + + vshPrint(ctl, "%s\n", virStorageVolGetKey(vol)); + virStorageVolFree(vol); + return true; +} + +/* + * "vol-path" command + */ +static const vshCmdInfo info_vol_path[] = { + {"help", N_("returns the volume path for a given volume name or key")}, + {"desc", ""}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_vol_path[] = { + {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")}, + {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; + +static bool +cmdVolPath(vshControl *ctl, const vshCmd *cmd) +{ + virStorageVolPtr vol; + char * StorageVolPath; + + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; + + if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) { + return false; + } + + if ((StorageVolPath = virStorageVolGetPath(vol)) == NULL) { + virStorageVolFree(vol); + return false; + } + + vshPrint(ctl, "%s\n", StorageVolPath); + VIR_FREE(StorageVolPath); + virStorageVolFree(vol); + return true; +} diff --git a/tools/virsh.c b/tools/virsh.c index af6bce00a408cac61162d6d2ca76f12cf53acc3f..5b5b1c4aac8045d6391bcf400197c1532d2e35e7 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -371,16 +371,6 @@ static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, vshCommandOptPoolBy(_ctl, _cmd, _optname, _name, \ VSH_BYUUID|VSH_BYNAME) -static virStorageVolPtr vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char *pooloptname, - const char **name, int flag); - -/* default is lookup by Name and UUID */ -#define vshCommandOptVol(_ctl, _cmd, _optname, _pooloptname, _name) \ - vshCommandOptVolBy(_ctl, _cmd, _optname, _pooloptname, _name, \ - VSH_BYUUID|VSH_BYNAME) - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name); @@ -4158,1632 +4148,264 @@ cmdPoolDiscoverSources(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED) return false; if (srcSpecFile && virFileReadAll(srcSpecFile, VIRSH_MAX_XML_FILE, &srcSpec) < 0) - return false; - - srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); - VIR_FREE(srcSpec); - if (srcList == NULL) { - vshError(ctl, _("Failed to find any %s pool sources"), type); - return false; - } - vshPrint(ctl, "%s", srcList); - VIR_FREE(srcList); - - return true; -} - - -/* - * "pool-info" command - */ -static const vshCmdInfo info_pool_info[] = { - {"help", N_("storage pool information")}, - {"desc", N_("Returns basic information about the storage pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_info[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolInfo info; - virStoragePoolPtr pool; - int autostart = 0; - int persistent = 0; - bool ret = true; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - return false; - - vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool)); - - if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) - vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); - - if (virStoragePoolGetInfo(pool, &info) == 0) { - double val; - const char *unit; - switch (info.state) { - case VIR_STORAGE_POOL_INACTIVE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inactive")); - break; - case VIR_STORAGE_POOL_BUILDING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("building")); - break; - case VIR_STORAGE_POOL_RUNNING: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("running")); - break; - case VIR_STORAGE_POOL_DEGRADED: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("degraded")); - break; - case VIR_STORAGE_POOL_INACCESSIBLE: - vshPrint(ctl, "%-15s %s\n", _("State:"), - _("inaccessible")); - break; - } - - /* Check and display whether the pool is persistent or not */ - persistent = virStoragePoolIsPersistent(pool); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool 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 pool is autostarted or not */ - virStoragePoolGetAutostart(pool, &autostart); - vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", - autostart); - if (autostart < 0) - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); - else - vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); - - if (info.state == VIR_STORAGE_POOL_RUNNING || - info.state == VIR_STORAGE_POOL_DEGRADED) { - val = prettyCapacity(info.capacity, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); - - val = prettyCapacity(info.allocation, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - - val = prettyCapacity(info.available, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); - } - } else { - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-name" command - */ -static const vshCmdInfo info_pool_name[] = { - {"help", N_("convert a pool UUID to pool name")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_name[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolName(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYUUID))) - return false; - - vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); - virStoragePoolFree(pool); - return true; -} - - -/* - * "pool-start" command - */ -static const vshCmdInfo info_pool_start[] = { - {"help", N_("start a (previously defined) inactive pool")}, - {"desc", N_("Start a pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_start[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolStart(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolCreate(pool, 0) == 0) { - vshPrint(ctl, _("Pool %s started\n"), name); - } else { - vshError(ctl, _("Failed to start pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "vol-create-as" command - */ -static const vshCmdInfo info_vol_create_as[] = { - {"help", N_("create a volume from a set of args")}, - {"desc", N_("Create a vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create_as[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {"name", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name of the volume")}, - {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("size of the vol, as scaled integer (default bytes)")}, - {"allocation", VSH_OT_STRING, 0, - N_("initial allocation size, as scaled integer (default bytes)")}, - {"format", VSH_OT_STRING, 0, - N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")}, - {"backing-vol", VSH_OT_STRING, 0, - N_("the backing volume if taking a snapshot")}, - {"backing-vol-format", VSH_OT_STRING, 0, - N_("format of backing volume if taking a snapshot")}, - {NULL, 0, 0, NULL} -}; - -static int -vshVolSize(const char *data, unsigned long long *val) -{ - char *end; - if (virStrToLong_ull(data, &end, 10, val) < 0) - return -1; - return virScaleInteger(val, end, 1, ULLONG_MAX); -} - -static bool -cmdVolCreateAs(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - virStorageVolPtr vol; - char *xml; - const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL; - const char *snapshotStrVol = NULL, *snapshotStrFormat = NULL; - unsigned long long capacity, allocation = 0; - virBuffer buf = VIR_BUFFER_INITIALIZER; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (vshCommandOptString(cmd, "name", &name) <= 0) - goto cleanup; - - if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) - goto cleanup; - - if (vshVolSize(capacityStr, &capacity) < 0) { - vshError(ctl, _("Malformed size %s"), capacityStr); - goto cleanup; - } - - if (vshCommandOptString(cmd, "allocation", &allocationStr) > 0 && - vshVolSize(allocationStr, &allocation) < 0) { - vshError(ctl, _("Malformed size %s"), allocationStr); - goto cleanup; - } - - if (vshCommandOptString(cmd, "format", &format) < 0 || - vshCommandOptString(cmd, "backing-vol", &snapshotStrVol) < 0 || - vshCommandOptString(cmd, "backing-vol-format", - &snapshotStrFormat) < 0) { - vshError(ctl, "%s", _("missing argument")); - goto cleanup; - } - - - virBufferAddLit(&buf, "\n"); - virBufferAsprintf(&buf, " %s\n", name); - virBufferAsprintf(&buf, " %llu\n", capacity); - if (allocationStr) - virBufferAsprintf(&buf, " %llu\n", allocation); - - if (format) { - virBufferAddLit(&buf, " \n"); - virBufferAsprintf(&buf, " \n",format); - virBufferAddLit(&buf, " \n"); - } - - /* Convert the snapshot parameters into backingStore XML */ - if (snapshotStrVol) { - /* Lookup snapshot backing volume. Try the backing-vol - * parameter as a name */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as name\n", - cmd->def->name, snapshotStrVol); - virStorageVolPtr snapVol = virStorageVolLookupByName(pool, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as name\n", - cmd->def->name, snapshotStrVol); - - if (snapVol == NULL) { - /* Snapshot backing volume not found by name. Try the - * backing-vol parameter as a key */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as key\n", - cmd->def->name, snapshotStrVol); - snapVol = virStorageVolLookupByKey(ctl->conn, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as key\n", - cmd->def->name, snapshotStrVol); - } - if (snapVol == NULL) { - /* Snapshot backing volume not found by key. Try the - * backing-vol parameter as a path */ - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Look up backing store volume '%s' as path\n", - cmd->def->name, snapshotStrVol); - snapVol = virStorageVolLookupByPath(ctl->conn, snapshotStrVol); - if (snapVol) - vshDebug(ctl, VSH_ERR_DEBUG, - "%s: Backing store volume found using '%s' as path\n", - cmd->def->name, snapshotStrVol); - } - if (snapVol == NULL) { - vshError(ctl, _("failed to get vol '%s'"), snapshotStrVol); - goto cleanup; - } - - char *snapshotStrVolPath; - if ((snapshotStrVolPath = virStorageVolGetPath(snapVol)) == NULL) { - virStorageVolFree(snapVol); - goto cleanup; - } - - /* Create XML for the backing store */ - virBufferAddLit(&buf, " \n"); - virBufferAsprintf(&buf, " %s\n",snapshotStrVolPath); - if (snapshotStrFormat) - virBufferAsprintf(&buf, " \n",snapshotStrFormat); - virBufferAddLit(&buf, " \n"); - - /* Cleanup snapshot allocations */ - VIR_FREE(snapshotStrVolPath); - virStorageVolFree(snapVol); - } - - virBufferAddLit(&buf, "\n"); - - if (virBufferError(&buf)) { - vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); - goto cleanup; - } - xml = virBufferContentAndReset(&buf); - vol = virStorageVolCreateXML(pool, xml, 0); - VIR_FREE(xml); - virStoragePoolFree(pool); - - if (vol != NULL) { - vshPrint(ctl, _("Vol %s created\n"), name); - virStorageVolFree(vol); - return true; - } else { - vshError(ctl, _("Failed to create vol %s"), name); - return false; - } - - cleanup: - virBufferFreeAndReset(&buf); - virStoragePoolFree(pool); - return false; -} - - -/* - * "pool-undefine" command - */ -static const vshCmdInfo info_pool_undefine[] = { - {"help", N_("undefine an inactive pool")}, - {"desc", N_("Undefine the configuration for an inactive pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_undefine[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) - return false; - - if (virStoragePoolUndefine(pool) == 0) { - vshPrint(ctl, _("Pool %s has been undefined\n"), name); - } else { - vshError(ctl, _("Failed to undefine pool %s"), name); - ret = false; - } - - virStoragePoolFree(pool); - return ret; -} - - -/* - * "pool-uuid" command - */ -static const vshCmdInfo info_pool_uuid[] = { - {"help", N_("convert a pool name to pool UUID")}, - {"desc", ""}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_pool_uuid[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - char uuid[VIR_UUID_STRING_BUFLEN]; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (virStoragePoolGetUUIDString(pool, uuid) != -1) - vshPrint(ctl, "%s\n", uuid); - else - vshError(ctl, "%s", _("failed to get pool UUID")); - - virStoragePoolFree(pool); - return true; -} - - -/* - * "vol-create" command - */ -static const vshCmdInfo info_vol_create[] = { - {"help", N_("create a vol from an XML file")}, - {"desc", N_("Create a vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolCreate(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool; - virStorageVolPtr vol; - const char *from = NULL; - bool ret = true; - char *buffer; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, - VSH_BYNAME))) - return false; - - if (vshCommandOptString(cmd, "file", &from) <= 0) { - virStoragePoolFree(pool); - return false; - } - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { - virshReportError(ctl); - virStoragePoolFree(pool); - return false; - } - - vol = virStorageVolCreateXML(pool, buffer, 0); - VIR_FREE(buffer); - virStoragePoolFree(pool); - - if (vol != NULL) { - vshPrint(ctl, _("Vol %s created from %s\n"), - virStorageVolGetName(vol), from); - virStorageVolFree(vol); - } else { - vshError(ctl, _("Failed to create vol from %s"), from); - ret = false; - } - return ret; -} - -/* - * "vol-create-from" command - */ -static const vshCmdInfo info_vol_create_from[] = { - {"help", N_("create a vol, using another volume as input")}, - {"desc", N_("Create a vol from an existing volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_create_from[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file containing an XML vol description")}, - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("input vol name or key")}, - {"inputpool", VSH_OT_STRING, 0, N_("pool name or uuid of the input volume's pool")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolCreateFrom(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr pool = NULL; - virStorageVolPtr newvol = NULL, inputvol = NULL; - const char *from = NULL; - bool ret = false; - char *buffer = NULL; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - goto cleanup; - - if (vshCommandOptString(cmd, "file", &from) <= 0) { - goto cleanup; - } - - if (!(inputvol = vshCommandOptVol(ctl, cmd, "vol", "inputpool", NULL))) - goto cleanup; - - if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0) { - virshReportError(ctl); - goto cleanup; - } - - newvol = virStorageVolCreateXMLFrom(pool, buffer, inputvol, 0); - - if (newvol != NULL) { - vshPrint(ctl, _("Vol %s created from input vol %s\n"), - virStorageVolGetName(newvol), virStorageVolGetName(inputvol)); - } else { - vshError(ctl, _("Failed to create vol from %s"), from); - goto cleanup; - } - - ret = true; -cleanup: - VIR_FREE(buffer); - if (pool) - virStoragePoolFree(pool); - if (inputvol) - virStorageVolFree(inputvol); - if (newvol) - virStorageVolFree(newvol); - return ret; -} - -static xmlChar * -makeCloneXML(const char *origxml, const char *newname) -{ - - xmlDocPtr doc = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlXPathObjectPtr obj = NULL; - xmlChar *newxml = NULL; - int size; - - doc = virXMLParseStringCtxt(origxml, _("(volume_definition)"), &ctxt); - if (!doc) - goto cleanup; - - obj = xmlXPathEval(BAD_CAST "/volume/name", ctxt); - if (obj == NULL || obj->nodesetval == NULL || - obj->nodesetval->nodeTab == NULL) - goto cleanup; - - xmlNodeSetContent(obj->nodesetval->nodeTab[0], (const xmlChar *)newname); - xmlDocDumpMemory(doc, &newxml, &size); - -cleanup: - xmlXPathFreeObject(obj); - xmlXPathFreeContext(ctxt); - xmlFreeDoc(doc); - return newxml; -} - -/* - * "vol-clone" command - */ -static const vshCmdInfo info_vol_clone[] = { - {"help", N_("clone a volume.")}, - {"desc", N_("Clone an existing volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_clone[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("orig vol name or key")}, - {"newname", VSH_OT_DATA, VSH_OFLAG_REQ, N_("clone name")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolClone(vshControl *ctl, const vshCmd *cmd) -{ - virStoragePoolPtr origpool = NULL; - virStorageVolPtr origvol = NULL, newvol = NULL; - const char *name = NULL; - char *origxml = NULL; - xmlChar *newxml = NULL; - bool ret = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (!(origvol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - goto cleanup; - - origpool = virStoragePoolLookupByVolume(origvol); - if (!origpool) { - vshError(ctl, "%s", _("failed to get parent pool")); - goto cleanup; - } - - if (vshCommandOptString(cmd, "newname", &name) <= 0) - goto cleanup; - - origxml = virStorageVolGetXMLDesc(origvol, 0); - if (!origxml) - goto cleanup; - - newxml = makeCloneXML(origxml, name); - if (!newxml) { - vshPrint(ctl, "%s", _("Failed to allocate XML buffer")); - goto cleanup; - } - - newvol = virStorageVolCreateXMLFrom(origpool, (char *) newxml, origvol, 0); - - if (newvol != NULL) { - vshPrint(ctl, _("Vol %s cloned from %s\n"), - virStorageVolGetName(newvol), virStorageVolGetName(origvol)); - } else { - vshError(ctl, _("Failed to clone vol from %s"), - virStorageVolGetName(origvol)); - goto cleanup; - } - - ret = true; - -cleanup: - VIR_FREE(origxml); - xmlFree(newxml); - if (origvol) - virStorageVolFree(origvol); - if (newvol) - virStorageVolFree(newvol); - if (origpool) - virStoragePoolFree(origpool); - return ret; -} - - -/* - * "vol-upload" command - */ -static const vshCmdInfo info_vol_upload[] = { - {"help", N_("upload a file into a volume")}, - {"desc", N_("Upload a file into a volume")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_upload[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"offset", VSH_OT_INT, 0, N_("volume offset to upload to") }, - {"length", VSH_OT_INT, 0, N_("amount of data to upload") }, - {NULL, 0, 0, NULL} -}; - -static int -cmdVolUploadSource(virStreamPtr st ATTRIBUTE_UNUSED, - char *bytes, size_t nbytes, void *opaque) -{ - int *fd = opaque; - - return saferead(*fd, bytes, nbytes); -} - -static bool -cmdVolUpload(vshControl *ctl, const vshCmd *cmd) -{ - const char *file = NULL; - virStorageVolPtr vol = NULL; - bool ret = false; - int fd = -1; - virStreamPtr st = NULL; - const char *name = NULL; - unsigned long long offset = 0, length = 0; - - if (!vshConnectionUsability(ctl, ctl->conn)) - goto cleanup; - - if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (vshCommandOptULongLong(cmd, "length", &length) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (vshCommandOptString(cmd, "file", &file) < 0) { - vshError(ctl, _("file must not be empty")); - goto cleanup; - } - - if ((fd = open(file, O_RDONLY)) < 0) { - vshError(ctl, _("cannot read %s"), file); - goto cleanup; - } - - st = virStreamNew(ctl->conn, 0); - if (virStorageVolUpload(vol, st, offset, length, 0) < 0) { - vshError(ctl, _("cannot upload to volume %s"), name); - goto cleanup; - } - - if (virStreamSendAll(st, cmdVolUploadSource, &fd) < 0) { - vshError(ctl, _("cannot send data to volume %s"), name); - goto cleanup; - } - - if (VIR_CLOSE(fd) < 0) { - vshError(ctl, _("cannot close file %s"), file); - virStreamAbort(st); - goto cleanup; - } - - if (virStreamFinish(st) < 0) { - vshError(ctl, _("cannot close volume %s"), name); - goto cleanup; - } - - ret = true; - -cleanup: - if (vol) - virStorageVolFree(vol); - if (st) - virStreamFree(st); - VIR_FORCE_CLOSE(fd); - return ret; -} - - - -/* - * "vol-download" command - */ -static const vshCmdInfo info_vol_download[] = { - {"help", N_("Download a volume to a file")}, - {"desc", N_("Download a volume to a file")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_download[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"file", VSH_OT_DATA, VSH_OFLAG_REQ, N_("file")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"offset", VSH_OT_INT, 0, N_("volume offset to download from") }, - {"length", VSH_OT_INT, 0, N_("amount of data to download") }, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDownload(vshControl *ctl, const vshCmd *cmd) -{ - const char *file = NULL; - virStorageVolPtr vol = NULL; - bool ret = false; - int fd = -1; - virStreamPtr st = NULL; - const char *name = NULL; - unsigned long long offset = 0, length = 0; - bool created = false; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (vshCommandOptULongLong(cmd, "offset", &offset) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (vshCommandOptULongLong(cmd, "length", &length) < 0) { - vshError(ctl, _("Unable to parse integer")); - return false; - } - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) - return false; - - if (vshCommandOptString(cmd, "file", &file) < 0) { - vshError(ctl, _("file must not be empty")); - goto cleanup; - } - - if ((fd = open(file, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) { - if (errno != EEXIST || - (fd = open(file, O_WRONLY|O_TRUNC, 0666)) < 0) { - vshError(ctl, _("cannot create %s"), file); - goto cleanup; - } - } else { - created = true; - } - - st = virStreamNew(ctl->conn, 0); - if (virStorageVolDownload(vol, st, offset, length, 0) < 0) { - vshError(ctl, _("cannot download from volume %s"), name); - goto cleanup; - } - - if (virStreamRecvAll(st, vshStreamSink, &fd) < 0) { - vshError(ctl, _("cannot receive data from volume %s"), name); - goto cleanup; - } - - if (VIR_CLOSE(fd) < 0) { - vshError(ctl, _("cannot close file %s"), file); - virStreamAbort(st); - goto cleanup; - } - - if (virStreamFinish(st) < 0) { - vshError(ctl, _("cannot close volume %s"), name); - goto cleanup; - } - - ret = true; - -cleanup: - VIR_FORCE_CLOSE(fd); - if (!ret && created) - unlink(file); - if (vol) - virStorageVolFree(vol); - if (st) - virStreamFree(st); - return ret; -} - - -/* - * "vol-delete" command - */ -static const vshCmdInfo info_vol_delete[] = { - {"help", N_("delete a vol")}, - {"desc", N_("Delete a given vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_delete[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDelete(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = true; - const char *name; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (virStorageVolDelete(vol, 0) == 0) { - vshPrint(ctl, _("Vol %s deleted\n"), name); - } else { - vshError(ctl, _("Failed to delete vol %s"), name); - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-wipe" command - */ -static const vshCmdInfo info_vol_wipe[] = { - {"help", N_("wipe a vol")}, - {"desc", N_("Ensure data previously on a volume is not accessible to future reads")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_wipe[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"algorithm", VSH_OT_STRING, 0, N_("perform selected wiping algorithm")}, - {NULL, 0, 0, NULL} -}; - -VIR_ENUM_DECL(virStorageVolWipeAlgorithm) -VIR_ENUM_IMPL(virStorageVolWipeAlgorithm, VIR_STORAGE_VOL_WIPE_ALG_LAST, - "zero", "nnsa", "dod", "bsi", "gutmann", "schneier", - "pfitzner7", "pfitzner33", "random"); - -static bool -cmdVolWipe(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = false; - const char *name; - const char *algorithm_str = NULL; - int algorithm = VIR_STORAGE_VOL_WIPE_ALG_ZERO; - int funcRet; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", &name))) { - return false; - } - - if (vshCommandOptString(cmd, "algorithm", &algorithm_str) < 0) { - vshError(ctl, "%s", _("missing argument")); - goto out; - } - - if (algorithm_str && - (algorithm = virStorageVolWipeAlgorithmTypeFromString(algorithm_str)) < 0) { - vshError(ctl, _("Unsupported algorithm '%s'"), algorithm_str); - goto out; - } - - if ((funcRet = virStorageVolWipePattern(vol, algorithm, 0)) < 0) { - if (last_error->code == VIR_ERR_NO_SUPPORT && - algorithm == VIR_STORAGE_VOL_WIPE_ALG_ZERO) - funcRet = virStorageVolWipe(vol, 0); - } - - if (funcRet < 0) { - vshError(ctl, _("Failed to wipe vol %s"), name); - goto out; - } - - vshPrint(ctl, _("Vol %s wiped\n"), name); - ret = true; -out: - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-info" command - */ -static const vshCmdInfo info_vol_info[] = { - {"help", N_("storage vol information")}, - {"desc", N_("Returns basic information about the storage vol.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_info[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolInfo(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolInfo info; - virStorageVolPtr vol; - bool ret = true; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - vshPrint(ctl, "%-15s %s\n", _("Name:"), virStorageVolGetName(vol)); - - if (virStorageVolGetInfo(vol, &info) == 0) { - double val; - const char *unit; - switch(info.type) { - case VIR_STORAGE_VOL_FILE: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("file")); - break; - - case VIR_STORAGE_VOL_BLOCK: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("block")); - break; - - case VIR_STORAGE_VOL_DIR: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir")); - break; - - case VIR_STORAGE_VOL_NETWORK: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network")); - break; - - default: - vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown")); - } - - val = prettyCapacity(info.capacity, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); - - val = prettyCapacity(info.allocation, &unit); - vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - } else { - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - -/* - * "vol-resize" command - */ -static const vshCmdInfo info_vol_resize[] = { - {"help", N_("resize a vol")}, - {"desc", N_("Resizes a storage volume.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_resize[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, - N_("new capacity for the vol, as scaled integer (default bytes)")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {"allocate", VSH_OT_BOOL, 0, - N_("allocate the new capacity, rather than leaving it sparse")}, - {"delta", VSH_OT_BOOL, 0, - N_("use capacity as a delta to current size, rather than the new size")}, - {"shrink", VSH_OT_BOOL, 0, N_("allow the resize to shrink the volume")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolResize(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - const char *capacityStr = NULL; - unsigned long long capacity = 0; - unsigned int flags = 0; - bool ret = false; - bool delta = false; - - if (vshCommandOptBool(cmd, "allocate")) - flags |= VIR_STORAGE_VOL_RESIZE_ALLOCATE; - if (vshCommandOptBool(cmd, "delta")) { - delta = true; - flags |= VIR_STORAGE_VOL_RESIZE_DELTA; - } - if (vshCommandOptBool(cmd, "shrink")) - flags |= VIR_STORAGE_VOL_RESIZE_SHRINK; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0) - goto cleanup; - virSkipSpaces(&capacityStr); - if (*capacityStr == '-') { - /* The API always requires a positive value; but we allow a - * negative value for convenience. */ - if (delta && vshCommandOptBool(cmd, "shrink")){ - capacityStr++; - } else { - vshError(ctl, "%s", - _("negative size requires --delta and --shrink")); - goto cleanup; - } - } - if (vshVolSize(capacityStr, &capacity) < 0) { - vshError(ctl, _("Malformed size %s"), capacityStr); - goto cleanup; - } - - if (virStorageVolResize(vol, capacity, flags) == 0) { - vshPrint(ctl, - delta ? _("Size of volume '%s' successfully changed by %s\n") - : _("Size of volume '%s' successfully changed to %s\n"), - virStorageVolGetName(vol), capacityStr); - ret = true; - } else { - vshError(ctl, - delta ? _("Failed to change size of volume '%s' by %s\n") - : _("Failed to change size of volume '%s' to %s\n"), - virStorageVolGetName(vol), capacityStr); - ret = false; - } - -cleanup: - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-dumpxml" command - */ -static const vshCmdInfo info_vol_dumpxml[] = { - {"help", N_("vol information in XML")}, - {"desc", N_("Output the vol information as an XML dump to stdout.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_dumpxml[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolDumpXML(vshControl *ctl, const vshCmd *cmd) -{ - virStorageVolPtr vol; - bool ret = true; - char *dump; - - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) - return false; - - dump = virStorageVolGetXMLDesc(vol, 0); - if (dump != NULL) { - vshPrint(ctl, "%s", dump); - VIR_FREE(dump); - } else { - ret = false; - } - - virStorageVolFree(vol); - return ret; -} - - -/* - * "vol-list" command - */ -static const vshCmdInfo info_vol_list[] = { - {"help", N_("list vols")}, - {"desc", N_("Returns list of vols by pool.")}, - {NULL, NULL} -}; - -static const vshCmdOptDef opts_vol_list[] = { - {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, - {"details", VSH_OT_BOOL, 0, N_("display extended details for volumes")}, - {NULL, 0, 0, NULL} -}; - -static bool -cmdVolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) -{ - virStorageVolInfo volumeInfo; - virStoragePoolPtr pool; - char **activeNames = NULL; - char *outputStr = NULL; - const char *unit; - double val; - bool details = vshCommandOptBool(cmd, "details"); - int numVolumes = 0, i; - int ret; - bool functionReturn; - int stringLength = 0; - size_t allocStrLength = 0, capStrLength = 0; - size_t nameStrLength = 0, pathStrLength = 0; - size_t typeStrLength = 0; - struct volInfoText { - char *allocation; - char *capacity; - char *path; - char *type; - }; - struct volInfoText *volInfoTexts = NULL; - - /* Check the connection to libvirtd daemon is still working */ - if (!vshConnectionUsability(ctl, ctl->conn)) - return false; - - /* Look up the pool information given to us by the user */ - if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) - return false; - - /* Determine the number of volumes in the pool */ - numVolumes = virStoragePoolNumOfVolumes(pool); - - if (numVolumes < 0) { - vshError(ctl, "%s", _("Failed to list storage volumes")); - virStoragePoolFree(pool); - return false; - } - - /* Retrieve the list of volume names in the pool */ - if (numVolumes > 0) { - activeNames = vshCalloc(ctl, numVolumes, sizeof(*activeNames)); - if ((numVolumes = virStoragePoolListVolumes(pool, activeNames, - numVolumes)) < 0) { - vshError(ctl, "%s", _("Failed to list active vols")); - VIR_FREE(activeNames); - virStoragePoolFree(pool); - return false; - } - - /* Sort the volume names */ - qsort(&activeNames[0], numVolumes, sizeof(*activeNames), vshNameSorter); - - /* Set aside memory for volume information pointers */ - volInfoTexts = vshCalloc(ctl, numVolumes, sizeof(*volInfoTexts)); - } - - /* Collect the rest of the volume information for display */ - for (i = 0; i < numVolumes; i++) { - /* Retrieve volume info */ - virStorageVolPtr vol = virStorageVolLookupByName(pool, - activeNames[i]); - - /* Retrieve the volume path */ - if ((volInfoTexts[i].path = virStorageVolGetPath(vol)) == NULL) { - /* Something went wrong retrieving a volume path, cope with it */ - volInfoTexts[i].path = vshStrdup(ctl, _("unknown")); - } - - /* If requested, retrieve volume type and sizing information */ - if (details) { - if (virStorageVolGetInfo(vol, &volumeInfo) != 0) { - /* Something went wrong retrieving volume info, cope with it */ - volInfoTexts[i].allocation = vshStrdup(ctl, _("unknown")); - volInfoTexts[i].capacity = vshStrdup(ctl, _("unknown")); - volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); - } else { - /* Convert the returned volume info into output strings */ - - /* Volume type */ - switch (volumeInfo.type) { - case VIR_STORAGE_VOL_FILE: - volInfoTexts[i].type = vshStrdup(ctl, _("file")); - break; - case VIR_STORAGE_VOL_BLOCK: - volInfoTexts[i].type = vshStrdup(ctl, _("block")); - break; - case VIR_STORAGE_VOL_DIR: - volInfoTexts[i].type = vshStrdup(ctl, _("dir")); - break; - default: - volInfoTexts[i].type = vshStrdup(ctl, _("unknown")); - } - - /* Create the capacity output string */ - val = prettyCapacity(volumeInfo.capacity, &unit); - ret = virAsprintf(&volInfoTexts[i].capacity, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - - /* Create the allocation output string */ - val = prettyCapacity(volumeInfo.allocation, &unit); - ret = virAsprintf(&volInfoTexts[i].allocation, - "%.2lf %s", val, unit); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } - } - - /* Remember the largest length for each output string. - * This lets us displaying header and volume information rows - * using a single, properly sized, printf style output string. - */ - - /* Keep the length of name string if longest so far */ - stringLength = strlen(activeNames[i]); - if (stringLength > nameStrLength) - nameStrLength = stringLength; - - /* Keep the length of path string if longest so far */ - stringLength = strlen(volInfoTexts[i].path); - if (stringLength > pathStrLength) - pathStrLength = stringLength; - - /* Keep the length of type string if longest so far */ - stringLength = strlen(volInfoTexts[i].type); - if (stringLength > typeStrLength) - typeStrLength = stringLength; - - /* Keep the length of capacity string if longest so far */ - stringLength = strlen(volInfoTexts[i].capacity); - if (stringLength > capStrLength) - capStrLength = stringLength; - - /* Keep the length of allocation string if longest so far */ - stringLength = strlen(volInfoTexts[i].allocation); - if (stringLength > allocStrLength) - allocStrLength = stringLength; - } - - /* Cleanup memory allocation */ - virStorageVolFree(vol); - } - - /* If the --details option wasn't selected, we output the volume - * info using the fixed string format from previous versions to - * maintain backward compatibility. - */ - - /* Output basic info then return if --details option not selected */ - if (!details) { - /* The old output format */ - vshPrintExtra(ctl, "%-20s %-40s\n", _("Name"), _("Path")); - vshPrintExtra(ctl, "-----------------------------------------\n"); - for (i = 0; i < numVolumes; i++) { - vshPrint(ctl, "%-20s %-40s\n", activeNames[i], - volInfoTexts[i].path); - } + return false; - /* Cleanup and return */ - functionReturn = true; - goto cleanup; + srcList = virConnectFindStoragePoolSources(ctl->conn, type, srcSpec, 0); + VIR_FREE(srcSpec); + if (srcList == NULL) { + vshError(ctl, _("Failed to find any %s pool sources"), type); + return false; } + vshPrint(ctl, "%s", srcList); + VIR_FREE(srcList); - /* We only get here if the --details option was selected. */ + return true; +} - /* Use the length of name header string if it's longest */ - stringLength = strlen(_("Name")); - if (stringLength > nameStrLength) - nameStrLength = stringLength; - /* Use the length of path header string if it's longest */ - stringLength = strlen(_("Path")); - if (stringLength > pathStrLength) - pathStrLength = stringLength; +/* + * "pool-info" command + */ +static const vshCmdInfo info_pool_info[] = { + {"help", N_("storage pool information")}, + {"desc", N_("Returns basic information about the storage pool.")}, + {NULL, NULL} +}; - /* Use the length of type header string if it's longest */ - stringLength = strlen(_("Type")); - if (stringLength > typeStrLength) - typeStrLength = stringLength; +static const vshCmdOptDef opts_pool_info[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, + {NULL, 0, 0, NULL} +}; - /* Use the length of capacity header string if it's longest */ - stringLength = strlen(_("Capacity")); - if (stringLength > capStrLength) - capStrLength = stringLength; +static bool +cmdPoolInfo(vshControl *ctl, const vshCmd *cmd) +{ + virStoragePoolInfo info; + virStoragePoolPtr pool; + int autostart = 0; + int persistent = 0; + bool ret = true; + char uuid[VIR_UUID_STRING_BUFLEN]; - /* Use the length of allocation header string if it's longest */ - stringLength = strlen(_("Allocation")); - if (stringLength > allocStrLength) - allocStrLength = stringLength; + if (!vshConnectionUsability(ctl, ctl->conn)) + return false; - /* Display the string lengths for debugging */ - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest name string = %zu chars\n", nameStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest path string = %zu chars\n", pathStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest type string = %zu chars\n", typeStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest capacity string = %zu chars\n", capStrLength); - vshDebug(ctl, VSH_ERR_DEBUG, - "Longest allocation string = %zu chars\n", allocStrLength); + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", NULL))) + return false; - /* Create the output template */ - ret = virAsprintf(&outputStr, - "%%-%lus %%-%lus %%-%lus %%%lus %%%lus\n", - (unsigned long) nameStrLength, - (unsigned long) pathStrLength, - (unsigned long) typeStrLength, - (unsigned long) capStrLength, - (unsigned long) allocStrLength); - if (ret < 0) { - /* An error occurred creating the string, return */ - goto asprintf_failure; - } + vshPrint(ctl, "%-15s %s\n", _("Name:"), virStoragePoolGetName(pool)); - /* Display the header */ - vshPrint(ctl, outputStr, _("Name"), _("Path"), _("Type"), - ("Capacity"), _("Allocation")); - for (i = nameStrLength + pathStrLength + typeStrLength - + capStrLength + allocStrLength - + 8; i > 0; i--) - vshPrintExtra(ctl, "-"); - vshPrintExtra(ctl, "\n"); + if (virStoragePoolGetUUIDString(pool, &uuid[0])==0) + vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid); - /* Display the volume info rows */ - for (i = 0; i < numVolumes; i++) { - vshPrint(ctl, outputStr, - activeNames[i], - volInfoTexts[i].path, - volInfoTexts[i].type, - volInfoTexts[i].capacity, - volInfoTexts[i].allocation); - } + if (virStoragePoolGetInfo(pool, &info) == 0) { + double val; + const char *unit; + switch (info.state) { + case VIR_STORAGE_POOL_INACTIVE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inactive")); + break; + case VIR_STORAGE_POOL_BUILDING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("building")); + break; + case VIR_STORAGE_POOL_RUNNING: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("running")); + break; + case VIR_STORAGE_POOL_DEGRADED: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("degraded")); + break; + case VIR_STORAGE_POOL_INACCESSIBLE: + vshPrint(ctl, "%-15s %s\n", _("State:"), + _("inaccessible")); + break; + } - /* Cleanup and return */ - functionReturn = true; - goto cleanup; + /* Check and display whether the pool is persistent or not */ + persistent = virStoragePoolIsPersistent(pool); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool 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")); -asprintf_failure: + /* Check and display whether the pool is autostarted or not */ + virStoragePoolGetAutostart(pool, &autostart); + vshDebug(ctl, VSH_ERR_DEBUG, "Pool autostart flag value: %d\n", + autostart); + if (autostart < 0) + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart")); + else + vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no")); - /* Display an appropriate error message then cleanup and return */ - switch (errno) { - case ENOMEM: - /* Couldn't allocate memory */ - vshError(ctl, "%s", _("Out of memory")); - break; - default: - /* Some other error */ - vshError(ctl, _("virAsprintf failed (errno %d)"), errno); - } - functionReturn = false; + if (info.state == VIR_STORAGE_POOL_RUNNING || + info.state == VIR_STORAGE_POOL_DEGRADED) { + val = prettyCapacity(info.capacity, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val, unit); -cleanup: + val = prettyCapacity(info.allocation, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val, unit); - /* Safely free the memory allocated in this function */ - for (i = 0; i < numVolumes; i++) { - /* Cleanup the memory for one volume info structure per loop */ - VIR_FREE(volInfoTexts[i].path); - VIR_FREE(volInfoTexts[i].type); - VIR_FREE(volInfoTexts[i].capacity); - VIR_FREE(volInfoTexts[i].allocation); - VIR_FREE(activeNames[i]); + val = prettyCapacity(info.available, &unit); + vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val, unit); + } + } else { + ret = false; } - /* Cleanup remaining memory */ - VIR_FREE(outputStr); - VIR_FREE(volInfoTexts); - VIR_FREE(activeNames); virStoragePoolFree(pool); - - /* Return the desired value */ - return functionReturn; + return ret; } /* - * "vol-name" command + * "pool-name" command */ -static const vshCmdInfo info_vol_name[] = { - {"help", N_("returns the volume name for a given volume key or path")}, +static const vshCmdInfo info_pool_name[] = { + {"help", N_("convert a pool UUID to pool name")}, {"desc", ""}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_name[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, +static const vshCmdOptDef opts_pool_name[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool uuid")}, {NULL, 0, 0, NULL} }; static bool -cmdVolName(vshControl *ctl, const vshCmd *cmd) +cmdPoolName(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; + virStoragePoolPtr pool; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - - if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, - VSH_BYUUID))) + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYUUID))) return false; - vshPrint(ctl, "%s\n", virStorageVolGetName(vol)); - virStorageVolFree(vol); + vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + virStoragePoolFree(pool); return true; } /* - * "vol-pool" command + * "pool-start" command */ -static const vshCmdInfo info_vol_pool[] = { - {"help", N_("returns the storage pool for a given volume key or path")}, - {"desc", ""}, +static const vshCmdInfo info_pool_start[] = { + {"help", N_("start a (previously defined) inactive pool")}, + {"desc", N_("Start a pool.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_pool[] = { - {"uuid", VSH_OT_BOOL, 0, N_("return the pool uuid rather than pool name")}, - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume key or path")}, +static const vshCmdOptDef opts_pool_start[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("name or uuid of the inactive pool")}, {NULL, 0, 0, NULL} }; static bool -cmdVolPool(vshControl *ctl, const vshCmd *cmd) +cmdPoolStart(vshControl *ctl, const vshCmd *cmd) { virStoragePoolPtr pool; - virStorageVolPtr vol; - char uuid[VIR_UUID_STRING_BUFLEN]; + bool ret = true; + const char *name = NULL; - /* Check the connection to libvirtd daemon is still working */ if (!vshConnectionUsability(ctl, ctl->conn)) return false; - /* Use the supplied string to locate the volume */ - if (!(vol = vshCommandOptVolBy(ctl, cmd, "vol", NULL, NULL, - VSH_BYUUID))) { - return false; - } - - /* Look up the parent storage pool for the volume */ - pool = virStoragePoolLookupByVolume(vol); - if (pool == NULL) { - vshError(ctl, "%s", _("failed to get parent pool")); - virStorageVolFree(vol); - return false; - } + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) + return false; - /* Return the requested details of the parent storage pool */ - if (vshCommandOptBool(cmd, "uuid")) { - /* Retrieve and return pool UUID string */ - if (virStoragePoolGetUUIDString(pool, &uuid[0]) == 0) - vshPrint(ctl, "%s\n", uuid); + if (virStoragePoolCreate(pool, 0) == 0) { + vshPrint(ctl, _("Pool %s started\n"), name); } else { - /* Return the storage pool name */ - vshPrint(ctl, "%s\n", virStoragePoolGetName(pool)); + vshError(ctl, _("Failed to start pool %s"), name); + ret = false; } - /* Cleanup */ - virStorageVolFree(vol); virStoragePoolFree(pool); - return true; + return ret; } - /* - * "vol-key" command + * "pool-undefine" command */ -static const vshCmdInfo info_vol_key[] = { - {"help", N_("returns the volume key for a given volume name or path")}, - {"desc", ""}, +static const vshCmdInfo info_pool_undefine[] = { + {"help", N_("undefine an inactive pool")}, + {"desc", N_("Undefine the configuration for an inactive pool.")}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_key[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or path")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, +static const vshCmdOptDef opts_pool_undefine[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")}, {NULL, 0, 0, NULL} }; static bool -cmdVolKey(vshControl *ctl, const vshCmd *cmd) +cmdPoolUndefine(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; + virStoragePoolPtr pool; + bool ret = true; + const char *name; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) + if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name))) return false; - vshPrint(ctl, "%s\n", virStorageVolGetKey(vol)); - virStorageVolFree(vol); - return true; -} + if (virStoragePoolUndefine(pool) == 0) { + vshPrint(ctl, _("Pool %s has been undefined\n"), name); + } else { + vshError(ctl, _("Failed to undefine pool %s"), name); + ret = false; + } + virStoragePoolFree(pool); + return ret; +} /* - * "vol-path" command + * "pool-uuid" command */ -static const vshCmdInfo info_vol_path[] = { - {"help", N_("returns the volume path for a given volume name or key")}, +static const vshCmdInfo info_pool_uuid[] = { + {"help", N_("convert a pool name to pool UUID")}, {"desc", ""}, {NULL, NULL} }; -static const vshCmdOptDef opts_vol_path[] = { - {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("volume name or key")}, - {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")}, +static const vshCmdOptDef opts_pool_uuid[] = { + {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name")}, {NULL, 0, 0, NULL} }; static bool -cmdVolPath(vshControl *ctl, const vshCmd *cmd) +cmdPoolUuid(vshControl *ctl, const vshCmd *cmd) { - virStorageVolPtr vol; - char * StorageVolPath; + virStoragePoolPtr pool; + char uuid[VIR_UUID_STRING_BUFLEN]; if (!vshConnectionUsability(ctl, ctl->conn)) return false; - if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL))) { + if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, + VSH_BYNAME))) return false; - } - if ((StorageVolPath = virStorageVolGetPath(vol)) == NULL) { - virStorageVolFree(vol); - return false; - } + if (virStoragePoolGetUUIDString(pool, uuid) != -1) + vshPrint(ctl, "%s\n", uuid); + else + vshError(ctl, "%s", _("failed to get pool UUID")); - vshPrint(ctl, "%s\n", StorageVolPath); - VIR_FREE(StorageVolPath); - virStorageVolFree(vol); + virStoragePoolFree(pool); return true; } - /* * "secret-define" command */ @@ -9617,66 +8239,6 @@ vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname, return pool; } -static virStorageVolPtr -vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd, - const char *optname, - const char *pooloptname, - const char **name, int flag) -{ - virStorageVolPtr vol = NULL; - virStoragePoolPtr pool = NULL; - const char *n = NULL, *p = NULL; - - if (vshCommandOptString(cmd, optname, &n) <= 0) - return NULL; - - if (pooloptname != NULL && vshCommandOptString(cmd, pooloptname, &p) < 0) { - vshError(ctl, "%s", _("missing option")); - return NULL; - } - - if (p) - pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flag); - - vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n", - cmd->def->name, optname, n); - - if (name) - *name = n; - - /* try it by name */ - if (pool && (flag & VSH_BYNAME)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n", - cmd->def->name, optname); - vol = virStorageVolLookupByName(pool, n); - } - /* try it by key */ - if (vol == NULL && (flag & VSH_BYUUID)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n", - cmd->def->name, optname); - vol = virStorageVolLookupByKey(ctl->conn, n); - } - /* try it by path */ - if (vol == NULL && (flag & VSH_BYUUID)) { - vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n", - cmd->def->name, optname); - vol = virStorageVolLookupByPath(ctl->conn, n); - } - - if (!vol) { - if (pool) - vshError(ctl, _("failed to get vol '%s'"), n); - else - vshError(ctl, _("failed to get vol '%s', specifying --%s " - "might help"), n, pooloptname); - } - - if (pool) - virStoragePoolFree(pool); - - return vol; -} - static virSecretPtr vshCommandOptSecret(vshControl *ctl, const vshCmd *cmd, const char **name) { @@ -11170,6 +9732,8 @@ static const vshCmdDef storagePoolCmds[] = { {NULL, NULL, NULL, NULL, 0} }; +#include "virsh-volume.c" + static const vshCmdDef storageVolCmds[] = { {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone, 0}, {"vol-create-as", cmdVolCreateAs, opts_vol_create_as,