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,