Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
---
po/POTFILES.in | 2 +
tools/Makefile.am | 4 +
tools/virsh-fspool.c | 1728 ++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh-fspool.h | 36 ++
tools/virsh-item.c | 1274 +++++++++++++++++++++++++++++++++++++
tools/virsh-item.h | 37 ++
tools/virsh.c | 4 +
tools/virsh.h | 9 +
8 files changed, 3094 insertions(+)
create mode 100644 tools/virsh-fspool.c
create mode 100644 tools/virsh-fspool.h
create mode 100644 tools/virsh-item.c
create mode 100644 tools/virsh-item.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 0fc3b79..7f8cdfa 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -289,8 +289,10 @@ tools/virsh-console.c
tools/virsh-domain-monitor.c
tools/virsh-domain.c
tools/virsh-edit.c
+tools/virsh-fspool.c
tools/virsh-host.c
tools/virsh-interface.c
+tools/virsh-item.c
tools/virsh-network.c
tools/virsh-nodedev.c
tools/virsh-nwfilter.c
diff --git a/tools/Makefile.am b/tools/Makefile.am
index a01c58d..a55550f 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -71,6 +71,8 @@ EXTRA_DIST = \
virsh-nwfilter.c virsh-pool.c \
virsh-secret.c virsh-snapshot.c \
virsh-volume.c \
+ virsh-fspool.c \
+ virsh-item.c \
$(PODFILES) \
$(MANINFILES) \
$(NULL)
@@ -205,9 +207,11 @@ virsh_SOURCES = \
virsh-nodedev.c virsh-nodedev.h \
virsh-nwfilter.c virsh-nwfilter.h \
virsh-pool.c virsh-pool.h \
+ virsh-fspool.c virsh-fspool.h \
virsh-secret.c virsh-secret.h \
virsh-snapshot.c virsh-snapshot.h \
virsh-volume.c virsh-volume.h \
+ virsh-item.c virsh-item.h \
$(NULL)
virsh_LDFLAGS = \
diff --git a/tools/virsh-fspool.c b/tools/virsh-fspool.c
new file mode 100644
index 0000000..820c1c7
--- /dev/null
+++ b/tools/virsh-fspool.c
@@ -0,0 +1,1728 @@
+/*
+ * virsh-fspool.c: Commands to manage fspool
+ */
+
+#include <config.h>
+#include "virsh-fspool.h"
+
+#include "internal.h"
+#include "virbuffer.h"
+#include "viralloc.h"
+#include "virfile.h"
+#include "conf/fs_conf.h"
+#include "virstring.h"
+
+#define VIRSH_COMMON_OPT_FS_POOL_FULL \
+ VIRSH_COMMON_OPT_FS_POOL(N_("fspool name or uuid")) \
+
+#define VIRSH_COMMON_OPT_FS_POOL_BUILD \
+ {.name = "build", \
+ .type = VSH_OT_BOOL, \
+ .flags = 0, \
+ .help = N_("build the fspool as normal") \
+ } \
+
+#define VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE \
+ {.name = "no-overwrite", \
+ .type = VSH_OT_BOOL, \
+ .flags = 0, \
+ .help = N_("do not overwrite an existing fspool of this type") \
+ } \
+
+#define VIRSH_COMMON_OPT_FS_POOL_OVERWRITE \
+ {.name = "overwrite", \
+ .type = VSH_OT_BOOL, \
+ .flags = 0, \
+ .help = N_("overwrite any existing data") \
+ } \
+
+#define VIRSH_COMMON_OPT_FS_POOL_X_AS \
+ {.name = "name", \
+ .type = VSH_OT_DATA, \
+ .flags = VSH_OFLAG_REQ, \
+ .help = N_("name of the fspool") \
+ }, \
+ {.name = "type", \
+ .type = VSH_OT_DATA, \
+ .flags = VSH_OFLAG_REQ, \
+ .help = N_("type of the fspool") \
+ }, \
+ {.name = "print-xml", \
+ .type = VSH_OT_BOOL, \
+ .help = N_("print XML document, but don't define/create") \
+ }, \
+ {.name = "source-host", \
+ .type = VSH_OT_STRING, \
+ .help = N_("source-host for underlying storage") \
+ }, \
+ {.name = "source-path", \
+ .type = VSH_OT_STRING, \
+ .help = N_("source path for underlying storage") \
+ }, \
+ {.name = "source-name", \
+ .type = VSH_OT_STRING, \
+ .help = N_("source name for underlying storage") \
+ }, \
+ {.name = "target", \
+ .type = VSH_OT_STRING, \
+ .help = N_("target for underlying storage") \
+ }, \
+ {.name = "source-format", \
+ .type = VSH_OT_STRING, \
+ .help = N_("format for underlying storage") \
+ } \
+
+virFsPoolPtr
+virshCommandOptFsPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
+ const char **name, unsigned int flags)
+{
+ virFsPoolPtr fspool = NULL;
+ const char *n = NULL;
+ virshControlPtr priv = ctl->privData;
+
+ virCheckFlags(VIRSH_BYUUID | VIRSH_BYNAME, NULL);
+
+ if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
+ return NULL;
+
+ vshDebug(ctl, VSH_ERR_INFO, "%s: found option <%s>: %s\n",
+ cmd->def->name, optname, n);
+
+ if (name)
+ *name = n;
+
+ /* try it by UUID */
+ if ((flags & VIRSH_BYUUID) && strlen(n) == VIR_UUID_STRING_BUFLEN-1) {
+ vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as fspool UUID\n",
+ cmd->def->name, optname);
+ fspool = virFsPoolLookupByUUIDString(priv->conn, n);
+ }
+ /* try it by NAME */
+ if (!fspool && (flags & VIRSH_BYNAME)) {
+ vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as fspool NAME\n",
+ cmd->def->name, optname);
+ fspool = virFsPoolLookupByName(priv->conn, n);
+ }
+
+ if (!fspool)
+ vshError(ctl, _("failed to get fspool '%s'"), n);
+
+ return fspool;
+}
+
+/*
+ * "fspool-create" command
+ */
+static const vshCmdInfo info_fspool_create[] = {
+ {.name = "help",
+ .data = N_("create a fspool from an XML file")
+ },
+ {.name = "desc",
+ .data = N_("Create a fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_create[] = {
+ VIRSH_COMMON_OPT_FILE(N_("file containing an XML fspool description")),
+ VIRSH_COMMON_OPT_FS_POOL_BUILD,
+ VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE,
+ VIRSH_COMMON_OPT_FS_POOL_OVERWRITE,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolCreate(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ const char *from = NULL;
+ bool ret = true;
+ char *buffer;
+ bool build;
+ bool overwrite;
+ bool no_overwrite;
+ unsigned int flags = 0;
+ virshControlPtr priv = ctl->privData;
+
+ if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
+ return false;
+
+ build = vshCommandOptBool(cmd, "build");
+ overwrite = vshCommandOptBool(cmd, "overwrite");
+ no_overwrite = vshCommandOptBool(cmd, "no-overwrite");
+
+ VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite,
+ "no-overwrite", no_overwrite);
+
+ if (build)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD;
+ if (overwrite)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE;
+ if (no_overwrite)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE;
+
+ if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
+ return false;
+
+ fspool = virFsPoolCreateXML(priv->conn, buffer, flags);
+ VIR_FREE(buffer);
+
+ if (fspool != NULL) {
+ vshPrint(ctl, _("Fspool %s created from %s\n"),
+ virFsPoolGetName(fspool), from);
+ virFsPoolFree(fspool);
+ } else {
+ vshError(ctl, _("Failed to create fspool from %s"), from);
+ ret = false;
+ }
+ return ret;
+}
+
+static const vshCmdOptDef opts_fspool_define_as[] = {
+ VIRSH_COMMON_OPT_FS_POOL_X_AS,
+
+ {.name = NULL}
+};
+
+static int
+virshBuildFsPoolXML(vshControl *ctl,
+ const vshCmd *cmd,
+ const char **retname,
+ char **xml)
+{
+ const char *name = NULL, *type = NULL, *srcHost = NULL, *srcPath = NULL,
+ *srcName = NULL, *srcFormat = NULL, *target = NULL;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
+ goto cleanup;
+ if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
+ goto cleanup;
+
+ if (vshCommandOptStringReq(ctl, cmd, "source-host", &srcHost) < 0
||
+ vshCommandOptStringReq(ctl, cmd, "source-path", &srcPath) < 0
||
+ vshCommandOptStringReq(ctl, cmd, "source-name", &srcName) < 0
||
+ vshCommandOptStringReq(ctl, cmd, "source-format", &srcFormat) <
0 ||
+ vshCommandOptStringReq(ctl, cmd, "target", &target) < 0)
+ goto cleanup;
+
+ virBufferAsprintf(&buf, "<fspool type='%s'>\n", type);
+ virBufferAdjustIndent(&buf, 2);
+ virBufferAsprintf(&buf, "<name>%s</name>\n", name);
+ if (srcHost || srcPath || srcFormat || srcName) {
+ virBufferAddLit(&buf, "<source>\n");
+ virBufferAdjustIndent(&buf, 2);
+
+ if (srcHost)
+ virBufferAsprintf(&buf, "<host name='%s'/>\n",
srcHost);
+ if (srcPath)
+ virBufferAsprintf(&buf, "<dir path='%s'/>\n",
srcPath);
+ if (srcFormat)
+ virBufferAsprintf(&buf, "<format type='%s'/>\n",
srcFormat);
+ if (srcName)
+ virBufferAsprintf(&buf, "<name>%s</name>\n",
srcName);
+
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</source>\n");
+ }
+ if (target) {
+ virBufferAddLit(&buf, "<target>\n");
+ virBufferAdjustIndent(&buf, 2);
+ virBufferAsprintf(&buf, "<path>%s</path>\n", target);
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</target>\n");
+ }
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</fspool>\n");
+
+ if (virBufferError(&buf)) {
+ vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
+ return false;
+ }
+
+ *xml = virBufferContentAndReset(&buf);
+ *retname = name;
+ return true;
+
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ return false;
+}
+
+/*
+ * "fspool-autostart" command
+ */
+static const vshCmdInfo info_fspool_autostart[] = {
+ {.name = "help",
+ .data = N_("autostart a fspool")
+ },
+ {.name = "desc",
+ .data = N_("Configure a fspool to be automatically started at boot.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_autostart[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = "disable",
+ .type = VSH_OT_BOOL,
+ .help = N_("disable autostarting")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolAutostart(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ const char *name;
+ int autostart;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name)))
+ return false;
+
+ autostart = !vshCommandOptBool(cmd, "disable");
+
+ if (virFsPoolSetAutostart(fspool, autostart) < 0) {
+ if (autostart)
+ vshError(ctl, _("failed to mark fspool %s as autostarted"), name);
+ else
+ vshError(ctl, _("failed to unmark fspool %s as autostarted"),
name);
+ virFsPoolFree(fspool);
+ return false;
+ }
+
+ if (autostart)
+ vshPrint(ctl, _("Fspool %s marked as autostarted\n"), name);
+ else
+ vshPrint(ctl, _("Fspool %s unmarked as autostarted\n"), name);
+
+ virFsPoolFree(fspool);
+ return true;
+}
+
+/*
+ * "fspool-create-as" command
+ */
+static const vshCmdInfo info_fspool_create_as[] = {
+ {.name = "help",
+ .data = N_("create a fspool from a set of args")
+ },
+ {.name = "desc",
+ .data = N_("Create a fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_create_as[] = {
+ VIRSH_COMMON_OPT_FS_POOL_X_AS,
+ VIRSH_COMMON_OPT_FS_POOL_BUILD,
+ VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE,
+ VIRSH_COMMON_OPT_FS_POOL_OVERWRITE,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolCreateAs(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ const char *name;
+ char *xml;
+ bool printXML = vshCommandOptBool(cmd, "print-xml");
+ bool build;
+ bool overwrite;
+ bool no_overwrite;
+ unsigned int flags = 0;
+ virshControlPtr priv = ctl->privData;
+
+ build = vshCommandOptBool(cmd, "build");
+ overwrite = vshCommandOptBool(cmd, "overwrite");
+ no_overwrite = vshCommandOptBool(cmd, "no-overwrite");
+
+ VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite,
+ "no-overwrite", no_overwrite);
+
+ if (build)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD;
+ if (overwrite)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE;
+ if (no_overwrite)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE;
+
+ if (!virshBuildFsPoolXML(ctl, cmd, &name, &xml))
+ return false;
+
+ if (printXML) {
+ vshPrint(ctl, "%s", xml);
+ VIR_FREE(xml);
+ } else {
+ fspool = virFsPoolCreateXML(priv->conn, xml, flags);
+ VIR_FREE(xml);
+
+ if (fspool != NULL) {
+ vshPrint(ctl, _("Fsool %s created\n"), name);
+ virFsPoolFree(fspool);
+ } else {
+ vshError(ctl, _("Failed to create fspool %s"), name);
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * "fspool-define" command
+ */
+static const vshCmdInfo info_fspool_define[] = {
+ {.name = "help",
+ .data = N_("define an inactive persistent fspool or modify "
+ "an existing persistent one from an XML file")
+ },
+ {.name = "desc",
+ .data = N_("Define or modify a persistent fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_define[] = {
+ VIRSH_COMMON_OPT_FILE(N_("file containing an XML fspool description")),
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolDefine(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ const char *from = NULL;
+ bool ret = true;
+ char *buffer;
+ virshControlPtr priv = ctl->privData;
+
+ if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
+ return false;
+
+ if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
+ return false;
+
+ fspool = virFsPoolDefineXML(priv->conn, buffer, 0);
+ VIR_FREE(buffer);
+
+ if (fspool != NULL) {
+ vshPrint(ctl, _("Fsool %s defined from %s\n"),
+ virFsPoolGetName(fspool), from);
+ virFsPoolFree(fspool);
+ } else {
+ vshError(ctl, _("Failed to define fspool from %s"), from);
+ ret = false;
+ }
+ return ret;
+}
+
+/*
+ * "fspool-define-as" command
+ */
+static const vshCmdInfo info_fspool_define_as[] = {
+ {.name = "help",
+ .data = N_("define a fspool from a set of args")
+ },
+ {.name = "desc",
+ .data = N_("Define a fspool.")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolDefineAs(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ const char *name;
+ char *xml;
+ bool printXML = vshCommandOptBool(cmd, "print-xml");
+ virshControlPtr priv = ctl->privData;
+
+ if (!virshBuildFsPoolXML(ctl, cmd, &name, &xml))
+ return false;
+
+ if (printXML) {
+ vshPrint(ctl, "%s", xml);
+ VIR_FREE(xml);
+ } else {
+ fspool = virFsPoolDefineXML(priv->conn, xml, 0);
+ VIR_FREE(xml);
+
+ if (fspool != NULL) {
+ vshPrint(ctl, _("Fspool %s defined\n"), name);
+ virFsPoolFree(fspool);
+ } else {
+ vshError(ctl, _("Failed to define fspool %s"), name);
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * "fspool-build" command
+ */
+static const vshCmdInfo info_fspool_build[] = {
+ {.name = "help",
+ .data = N_("build a fspool")
+ },
+ {.name = "desc",
+ .data = N_("Build a given fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_build[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+ VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE,
+ VIRSH_COMMON_OPT_FS_POOL_OVERWRITE,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolBuild(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ bool ret = true;
+ const char *name;
+ unsigned int flags = 0;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name)))
+ return false;
+
+ if (vshCommandOptBool(cmd, "no-overwrite"))
+ flags |= VIR_FS_POOL_BUILD_NO_OVERWRITE;
+
+ if (vshCommandOptBool(cmd, "overwrite"))
+ flags |= VIR_FS_POOL_BUILD_OVERWRITE;
+
+ if (virFsPoolBuild(fspool, flags) == 0) {
+ vshPrint(ctl, _("Fspool %s built\n"), name);
+ } else {
+ vshError(ctl, _("Failed to build fspool %s"), name);
+ ret = false;
+ }
+
+ virFsPoolFree(fspool);
+
+ return ret;
+}
+
+/*
+ * "fspool-destroy" command
+ */
+static const vshCmdInfo info_fspool_destroy[] = {
+ {.name = "help",
+ .data = N_("stop a fspool")
+ },
+ {.name = "desc",
+ .data = N_("Forcefully stop a given fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_destroy[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolDestroy(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ bool ret = true;
+ const char *name;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name)))
+ return false;
+
+ if (virFsPoolDestroy(fspool) == 0) {
+ vshPrint(ctl, _("Fspool %s destroyed\n"), name);
+ } else {
+ vshError(ctl, _("Failed to destroy fspool %s"), name);
+ ret = false;
+ }
+
+ virFsPoolFree(fspool);
+ return ret;
+}
+
+/*
+ * "fspool-delete" command
+ */
+static const vshCmdInfo info_fspool_delete[] = {
+ {.name = "help",
+ .data = N_("delete a fspool")
+ },
+ {.name = "desc",
+ .data = N_("Delete a given fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_delete[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolDelete(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ bool ret = true;
+ const char *name;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name)))
+ return false;
+
+ if (virFsPoolDelete(fspool, 0) == 0) {
+ vshPrint(ctl, _("Pool %s deleted\n"), name);
+ } else {
+ vshError(ctl, _("Failed to delete fspool %s"), name);
+ ret = false;
+ }
+
+ virFsPoolFree(fspool);
+ return ret;
+}
+
+/*
+ * "fspool-refresh" command
+ */
+static const vshCmdInfo info_fspool_refresh[] = {
+ {.name = "help",
+ .data = N_("refresh a fspool")
+ },
+ {.name = "desc",
+ .data = N_("Refresh a given fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_refresh[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolRefresh(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ bool ret = true;
+ const char *name;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name)))
+ return false;
+
+ if (virFsPoolRefresh(fspool, 0) == 0) {
+ vshPrint(ctl, _("Pool %s refreshed\n"), name);
+ } else {
+ vshError(ctl, _("Failed to refresh fspool %s"), name);
+ ret = false;
+ }
+ virFsPoolFree(fspool);
+
+ return ret;
+}
+
+/*
+ * "fspool-dumpxml" command
+ */
+static const vshCmdInfo info_fspool_dumpxml[] = {
+ {.name = "help",
+ .data = N_("fspool information in XML")
+ },
+ {.name = "desc",
+ .data = N_("Output the fspool information as an XML dump to stdout.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_dumpxml[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = "inactive",
+ .type = VSH_OT_BOOL,
+ .help = N_("show inactive defined XML")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolDumpXML(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ bool ret = true;
+ bool inactive = vshCommandOptBool(cmd, "inactive");
+ unsigned int flags = 0;
+ char *dump;
+
+ if (inactive)
+ flags |= VIR_FS_XML_INACTIVE;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", NULL)))
+ return false;
+
+ dump = virFsPoolGetXMLDesc(fspool, flags);
+ if (dump != NULL) {
+ vshPrint(ctl, "%s", dump);
+ VIR_FREE(dump);
+ } else {
+ ret = false;
+ }
+
+ virFsPoolFree(fspool);
+ return ret;
+}
+
+static int
+virshFsPoolSorter(const void *a, const void *b)
+{
+ virFsPoolPtr *pa = (virFsPoolPtr *) a;
+ virFsPoolPtr *pb = (virFsPoolPtr *) b;
+
+ if (*pa && !*pb)
+ return -1;
+
+ if (!*pa)
+ return *pb != NULL;
+
+ return vshStrcasecmp(virFsPoolGetName(*pa),
+ virFsPoolGetName(*pb));
+}
+
+struct virshFsPoolList {
+ virFsPoolPtr *fspools;
+ size_t nfspools;
+};
+typedef struct virshFsPoolList *virshFsPoolListPtr;
+
+static void
+virshFsPoolListFree(virshFsPoolListPtr list)
+{
+ size_t i;
+
+ if (list && list->fspools) {
+ for (i = 0; i < list->nfspools; i++) {
+ if (list->fspools[i])
+ virFsPoolFree(list->fspools[i]);
+ }
+ VIR_FREE(list->fspools);
+ }
+ VIR_FREE(list);
+}
+
+static virshFsPoolListPtr
+virshFsPoolListCollect(vshControl *ctl,
+ unsigned int flags)
+{
+ virshFsPoolListPtr list = vshMalloc(ctl, sizeof(*list));
+ size_t i;
+ int ret;
+ char **names = NULL;
+ virFsPoolPtr fspool;
+ bool success = false;
+ size_t deleted = 0;
+ int persistent;
+ int autostart;
+ int nActivePools = 0;
+ int nInactivePools = 0;
+ int nAllPools = 0;
+ virshControlPtr priv = ctl->privData;
+
+ /* try the list with flags support (0.10.2 and later) */
+ if ((ret = virConnectListAllFsPools(priv->conn,
+ &list->fspools,
+ flags)) >= 0) {
+ list->nfspools = ret;
+ goto finished;
+ }
+
+ /* check if the command is actually supported */
+ if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
+ goto fallback;
+
+ if (last_error && last_error->code == VIR_ERR_INVALID_ARG) {
+ /* try the new API again but mask non-guaranteed flags */
+ unsigned int newflags = flags & (VIR_CONNECT_LIST_FS_POOLS_ACTIVE |
+ VIR_CONNECT_LIST_FS_POOLS_INACTIVE);
+ vshResetLibvirtError();
+ if ((ret = virConnectListAllFsPools(priv->conn, &list->fspools,
+ newflags)) >= 0) {
+ list->nfspools = ret;
+ goto filter;
+ }
+ }
+
+ /* there was an error during the first or second call */
+ vshError(ctl, "%s", _("Failed to list fspools"));
+ goto cleanup;
+
+
+ fallback:
+ /* fall back to old method (0.10.1 and older) */
+ vshResetLibvirtError();
+
+ /* There is no way to get the fspool type */
+ if (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_POOL_TYPE)) {
+ vshError(ctl, "%s", _("Filtering using --type is not supported
"
+ "by this libvirt"));
+ goto cleanup;
+ }
+
+ /* Get the number of active fspools */
+ if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) ||
+ VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE)) {
+ if ((nActivePools = virConnectNumOfFsPools(priv->conn)) < 0) {
+ vshError(ctl, "%s", _("Failed to get the number of active
fspools "));
+ goto cleanup;
+ }
+ }
+
+ /* Get the number of inactive fspools */
+ if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) ||
+ VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_INACTIVE)) {
+ if ((nInactivePools = virConnectNumOfDefinedFsPools(priv->conn)) < 0) {
+ vshError(ctl, "%s", _("Failed to get the number of inactive
fspools"));
+ goto cleanup;
+ }
+ }
+
+ nAllPools = nActivePools + nInactivePools;
+
+ if (nAllPools == 0)
+ return list;
+
+ names = vshMalloc(ctl, sizeof(char *) * nAllPools);
+
+ /* Retrieve a list of active storage fspool names */
+ if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) ||
+ VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE)) {
+ if (virConnectListFsPools(priv->conn,
+ names, nActivePools) < 0) {
+ vshError(ctl, "%s", _("Failed to list active fspools"));
+ goto cleanup;
+ }
+ }
+
+ /* Add the inactive storage fspools to the end of the name list */
+ if (!VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_ACTIVE) ||
+ VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_ACTIVE)) {
+ if (virConnectListDefinedFsPools(priv->conn,
+ &names[nActivePools],
+ nInactivePools) < 0) {
+ vshError(ctl, "%s", _("Failed to list inactive
fspools"));
+ goto cleanup;
+ }
+ }
+
+ list->fspools = vshMalloc(ctl, sizeof(virFsPoolPtr) * (nAllPools));
+ list->nfspools = 0;
+
+ /* get active fspools */
+ for (i = 0; i < nActivePools; i++) {
+ if (!(fspool = virFsPoolLookupByName(priv->conn, names[i])))
+ continue;
+ list->fspools[list->nfspools++] = fspool;
+ }
+
+ /* get inactive fspools */
+ for (i = 0; i < nInactivePools; i++) {
+ if (!(fspool = virFsPoolLookupByName(priv->conn, names[i])))
+ continue;
+ list->fspools[list->nfspools++] = fspool;
+ }
+
+ /* truncate fspools that weren't found */
+ deleted = nAllPools - list->nfspools;
+
+ filter:
+ /* filter list the list if the list was acquired by fallback means */
+ for (i = 0; i < list->nfspools; i++) {
+ fspool = list->fspools[i];
+
+ /* persistence filter */
+ if (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_PERSISTENT)) {
+ if ((persistent = virFsPoolIsPersistent(fspool)) < 0) {
+ vshError(ctl, "%s", _("Failed to get fspool persistence
info"));
+ goto cleanup;
+ }
+
+ if (!((VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_PERSISTENT) && persistent)
||
+ (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_TRANSIENT) &&
!persistent)))
+ goto remove_entry;
+ }
+
+ /* autostart filter */
+ if (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_FILTERS_AUTOSTART)) {
+ if (virFsPoolGetAutostart(fspool, &autostart) < 0) {
+ vshError(ctl, "%s", _("Failed to get fspool autostart
state"));
+ goto cleanup;
+ }
+
+ if (!((VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_AUTOSTART) && autostart)
||
+ (VSH_MATCH(VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART) &&
!autostart)))
+ goto remove_entry;
+ }
+
+ /* the fspool matched all filters, it may stay */
+ continue;
+
+ remove_entry:
+ /* the fspool has to be removed as it failed one of the filters */
+ virFsPoolFree(list->fspools[i]);
+ list->fspools[i] = NULL;
+ deleted++;
+ }
+
+ finished:
+ /* sort the list */
+ if (list->fspools && list->nfspools)
+ qsort(list->fspools, list->nfspools,
+ sizeof(*list->fspools), virshFsPoolSorter);
+
+ /* truncate the list if filter simulation deleted entries */
+ if (deleted)
+ VIR_SHRINK_N(list->fspools, list->nfspools, deleted);
+
+ success = true;
+
+ cleanup:
+ for (i = 0; i < nAllPools; i++)
+ VIR_FREE(names[i]);
+
+ if (!success) {
+ virshFsPoolListFree(list);
+ list = NULL;
+ }
+
+ VIR_FREE(names);
+ return list;
+}
+
+
+VIR_ENUM_DECL(virshFsPoolState)
+VIR_ENUM_IMPL(virshFsPoolState,
+ VIR_FS_POOL_STATE_LAST,
+ N_("inactive"),
+ N_("building"),
+ N_("running"))
+
+static const char *
+virshFsPoolStateToString(int state)
+{
+ const char *str = virshFsPoolStateTypeToString(state);
+ return str ? _(str) : _("unknown");
+}
+
+
+/*
+ * "fspool-list" command
+ */
+static const vshCmdInfo info_fspool_list[] = {
+ {.name = "help",
+ .data = N_("list fspools")
+ },
+ {.name = "desc",
+ .data = N_("Returns list of fspools.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_list[] = {
+ {.name = "inactive",
+ .type = VSH_OT_BOOL,
+ .help = N_("list inactive fspools")
+ },
+ {.name = "all",
+ .type = VSH_OT_BOOL,
+ .help = N_("list inactive & active fspools")
+ },
+ {.name = "transient",
+ .type = VSH_OT_BOOL,
+ .help = N_("list transient fspools")
+ },
+ {.name = "persistent",
+ .type = VSH_OT_BOOL,
+ .help = N_("list persistent fspools")
+ },
+ {.name = "autostart",
+ .type = VSH_OT_BOOL,
+ .help = N_("list fspools with autostart enabled")
+ },
+ {.name = "no-autostart",
+ .type = VSH_OT_BOOL,
+ .help = N_("list fspools with autostart disabled")
+ },
+ {.name = "type",
+ .type = VSH_OT_STRING,
+ .help = N_("only list fspool of specified type(s) (if supported)")
+ },
+ {.name = "details",
+ .type = VSH_OT_BOOL,
+ .help = N_("display extended details for fspools")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+ virFsPoolInfo info;
+ size_t i;
+ bool ret = false;
+ size_t stringLength = 0, nameStrLength = 0;
+ size_t autostartStrLength = 0, persistStrLength = 0;
+ size_t stateStrLength = 0, capStrLength = 0;
+ size_t allocStrLength = 0, availStrLength = 0;
+ struct fspoolInfoText {
+ char *state;
+ char *autostart;
+ char *persistent;
+ char *capacity;
+ char *allocation;
+ char *available;
+ };
+ struct fspoolInfoText *fspoolInfoTexts = NULL;
+ unsigned int flags = VIR_CONNECT_LIST_FS_POOLS_ACTIVE;
+ virshFsPoolListPtr list = NULL;
+ const char *type = NULL;
+ bool details = vshCommandOptBool(cmd, "details");
+ bool inactive, all;
+ char *outputStr = NULL;
+
+ inactive = vshCommandOptBool(cmd, "inactive");
+ all = vshCommandOptBool(cmd, "all");
+
+ if (inactive)
+ flags = VIR_CONNECT_LIST_FS_POOLS_INACTIVE;
+
+ if (all)
+ flags = VIR_CONNECT_LIST_FS_POOLS_ACTIVE |
+ VIR_CONNECT_LIST_FS_POOLS_INACTIVE;
+
+ if (vshCommandOptBool(cmd, "autostart"))
+ flags |= VIR_CONNECT_LIST_FS_POOLS_AUTOSTART;
+
+ if (vshCommandOptBool(cmd, "no-autostart"))
+ flags |= VIR_CONNECT_LIST_FS_POOLS_NO_AUTOSTART;
+
+ if (vshCommandOptBool(cmd, "persistent"))
+ flags |= VIR_CONNECT_LIST_FS_POOLS_PERSISTENT;
+
+ if (vshCommandOptBool(cmd, "transient"))
+ flags |= VIR_CONNECT_LIST_FS_POOLS_TRANSIENT;
+
+ if (vshCommandOptStringReq(ctl, cmd, "type", &type) < 0)
+ return false;
+
+ if (type) {
+ int fspoolType = -1;
+ char **fspoolTypes = NULL;
+ int nfspoolTypes = 0;
+
+ if ((nfspoolTypes = vshStringToArray(type, &fspoolTypes)) < 0)
+ return false;
+
+ for (i = 0; i < nfspoolTypes; i++) {
+ if ((fspoolType = virFsPoolTypeFromString(fspoolTypes[i])) < 0) {
+ vshError(ctl, _("Invalid fspool type '%s'"),
fspoolTypes[i]);
+ virStringFreeList(fspoolTypes);
+ return false;
+ }
+
+ switch ((virFsPoolType) fspoolType) {
+ case VIR_FS_POOL_DIR:
+ flags |= VIR_CONNECT_LIST_FS_POOLS_DIR;
+ break;
+ case VIR_FS_POOL_LAST:
+ break;
+ }
+ }
+ virStringFreeList(fspoolTypes);
+ }
+
+ if (!(list = virshFsPoolListCollect(ctl, flags)))
+ goto cleanup;
+
+ fspoolInfoTexts = vshCalloc(ctl, list->nfspools, sizeof(*fspoolInfoTexts));
+
+ /* Collect the storage fspool information for display */
+ for (i = 0; i < list->nfspools; i++) {
+ int autostart = 0, persistent = 0;
+
+ /* Retrieve the autostart status of the fspool */
+ if (virFsPoolGetAutostart(list->fspools[i], &autostart) < 0)
+ fspoolInfoTexts[i].autostart = vshStrdup(ctl, _("no autostart"));
+ else
+ fspoolInfoTexts[i].autostart = vshStrdup(ctl, autostart ?
+ _("yes") :
_("no"));
+
+ /* Retrieve the persistence status of the fspool */
+ if (details) {
+ persistent = virFsPoolIsPersistent(list->fspools[i]);
+ vshDebug(ctl, VSH_ERR_DEBUG, "Persistent flag value: %d\n",
+ persistent);
+ if (persistent < 0)
+ fspoolInfoTexts[i].persistent = vshStrdup(ctl, _("unknown"));
+ else
+ fspoolInfoTexts[i].persistent = vshStrdup(ctl, persistent ?
+ _("yes") :
_("no"));
+
+ /* Keep the length of persistent string if longest so far */
+ stringLength = strlen(fspoolInfoTexts[i].persistent);
+ if (stringLength > persistStrLength)
+ persistStrLength = stringLength;
+ }
+
+ /* Collect further extended information about the fspool */
+ if (virFsPoolGetInfo(list->fspools[i], &info) != 0) {
+ /* Something went wrong retrieving fspool info, cope with it */
+ vshError(ctl, "%s", _("Could not retrieve fspool
information"));
+ fspoolInfoTexts[i].state = vshStrdup(ctl, _("unknown"));
+ if (details) {
+ fspoolInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
+ fspoolInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
+ fspoolInfoTexts[i].available = vshStrdup(ctl, _("unknown"));
+ }
+ } else {
+ /* Decide which state string to display */
+ if (details) {
+ const char *state = virshFsPoolStateToString(info.state);
+
+ fspoolInfoTexts[i].state = vshStrdup(ctl, state);
+
+ /* Create the fspool size related strings */
+ if (info.state == VIR_FS_POOL_RUNNING) {
+ double val;
+ const char *unit;
+
+ val = vshPrettyCapacity(info.capacity, &unit);
+ if (virAsprintf(&fspoolInfoTexts[i].capacity,
+ "%.2lf %s", val, unit) < 0)
+ goto cleanup;
+
+ val = vshPrettyCapacity(info.allocation, &unit);
+ if (virAsprintf(&fspoolInfoTexts[i].allocation,
+ "%.2lf %s", val, unit) < 0)
+ goto cleanup;
+
+ val = vshPrettyCapacity(info.available, &unit);
+ if (virAsprintf(&fspoolInfoTexts[i].available,
+ "%.2lf %s", val, unit) < 0)
+ goto cleanup;
+ } else {
+ /* Capacity related information isn't available */
+ fspoolInfoTexts[i].capacity = vshStrdup(ctl, _("-"));
+ fspoolInfoTexts[i].allocation = vshStrdup(ctl, _("-"));
+ fspoolInfoTexts[i].available = vshStrdup(ctl, _("-"));
+ }
+
+ /* Keep the length of capacity string if longest so far */
+ stringLength = strlen(fspoolInfoTexts[i].capacity);
+ if (stringLength > capStrLength)
+ capStrLength = stringLength;
+
+ /* Keep the length of allocation string if longest so far */
+ stringLength = strlen(fspoolInfoTexts[i].allocation);
+ if (stringLength > allocStrLength)
+ allocStrLength = stringLength;
+
+ /* Keep the length of available string if longest so far */
+ stringLength = strlen(fspoolInfoTexts[i].available);
+ if (stringLength > availStrLength)
+ availStrLength = stringLength;
+ } else {
+ /* --details option was not specified, only active/inactive
+ * state strings are used */
+ if (virFsPoolIsActive(list->fspools[i]))
+ fspoolInfoTexts[i].state = vshStrdup(ctl, _("active"));
+ else
+ fspoolInfoTexts[i].state = vshStrdup(ctl, _("inactive"));
+ }
+ }
+
+ /* Keep the length of name string if longest so far */
+ stringLength = strlen(virFsPoolGetName(list->fspools[i]));
+ if (stringLength > nameStrLength)
+ nameStrLength = stringLength;
+
+ /* Keep the length of state string if longest so far */
+ stringLength = strlen(fspoolInfoTexts[i].state);
+ if (stringLength > stateStrLength)
+ stateStrLength = stringLength;
+
+ /* Keep the length of autostart string if longest so far */
+ stringLength = strlen(fspoolInfoTexts[i].autostart);
+ if (stringLength > autostartStrLength)
+ autostartStrLength = stringLength;
+ }
+
+ /* If the --details option wasn't selected, we output the fspool
+ * 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) {
+ /* Output old style header */
+ vshPrintExtra(ctl, " %-20s %-10s %-10s\n", _("Name"),
_("State"),
+ _("Autostart"));
+ vshPrintExtra(ctl, "-------------------------------------------\n");
+
+ /* Output old style fspool info */
+ for (i = 0; i < list->nfspools; i++) {
+ const char *name = virFsPoolGetName(list->fspools[i]);
+ vshPrint(ctl, " %-20s %-10s %-10s\n",
+ name,
+ fspoolInfoTexts[i].state,
+ fspoolInfoTexts[i].autostart);
+ }
+
+ /* Cleanup and return */
+ ret = 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 state header string if it's longest */
+ stringLength = strlen(_("State"));
+ if (stringLength > stateStrLength)
+ stateStrLength = stringLength;
+
+ /* Use the length of autostart header string if it's longest */
+ stringLength = strlen(_("Autostart"));
+ if (stringLength > autostartStrLength)
+ autostartStrLength = stringLength;
+
+ /* Use the length of persistent header string if it's longest */
+ stringLength = strlen(_("Persistent"));
+ if (stringLength > persistStrLength)
+ persistStrLength = 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;
+
+ /* Use the length of available header string if it's longest */
+ stringLength = strlen(_("Available"));
+ if (stringLength > availStrLength)
+ availStrLength = stringLength;
+
+ /* Display the string lengths for debugging. */
+ vshDebug(ctl, VSH_ERR_DEBUG, "Longest name string = %lu chars\n",
+ (unsigned long) nameStrLength);
+ vshDebug(ctl, VSH_ERR_DEBUG, "Longest state string = %lu chars\n",
+ (unsigned long) stateStrLength);
+ vshDebug(ctl, VSH_ERR_DEBUG, "Longest autostart string = %lu chars\n",
+ (unsigned long) autostartStrLength);
+ vshDebug(ctl, VSH_ERR_DEBUG, "Longest persistent string = %lu chars\n",
+ (unsigned long) persistStrLength);
+ vshDebug(ctl, VSH_ERR_DEBUG, "Longest capacity string = %lu chars\n",
+ (unsigned long) capStrLength);
+ vshDebug(ctl, VSH_ERR_DEBUG, "Longest allocation string = %lu chars\n",
+ (unsigned long) allocStrLength);
+ vshDebug(ctl, VSH_ERR_DEBUG, "Longest available string = %lu chars\n",
+ (unsigned long) availStrLength);
+
+ /* Create the output template. Each column is sized according to
+ * the longest string.
+ */
+ if (virAsprintf(&outputStr,
+ " %%-%lus %%-%lus %%-%lus %%-%lus %%%lus %%%lus
%%%lus\n",
+ (unsigned long) nameStrLength,
+ (unsigned long) stateStrLength,
+ (unsigned long) autostartStrLength,
+ (unsigned long) persistStrLength,
+ (unsigned long) capStrLength,
+ (unsigned long) allocStrLength,
+ (unsigned long) availStrLength) < 0)
+ goto cleanup;
+
+ /* Display the header */
+ vshPrint(ctl, outputStr, _("Name"), _("State"),
_("Autostart"),
+ _("Persistent"), _("Capacity"),
_("Allocation"), _("Available"));
+ for (i = nameStrLength + stateStrLength + autostartStrLength
+ + persistStrLength + capStrLength
+ + allocStrLength + availStrLength
+ + 14; i > 0; i--)
+ vshPrintExtra(ctl, "-");
+ vshPrintExtra(ctl, "\n");
+
+ /* Display the fspool info rows */
+ for (i = 0; i < list->nfspools; i++) {
+ vshPrint(ctl, outputStr,
+ virFsPoolGetName(list->fspools[i]),
+ fspoolInfoTexts[i].state,
+ fspoolInfoTexts[i].autostart,
+ fspoolInfoTexts[i].persistent,
+ fspoolInfoTexts[i].capacity,
+ fspoolInfoTexts[i].allocation,
+ fspoolInfoTexts[i].available);
+ }
+
+ /* Cleanup and return */
+ ret = true;
+
+ cleanup:
+ VIR_FREE(outputStr);
+ if (list && list->nfspools) {
+ for (i = 0; i < list->nfspools; i++) {
+ VIR_FREE(fspoolInfoTexts[i].state);
+ VIR_FREE(fspoolInfoTexts[i].autostart);
+ VIR_FREE(fspoolInfoTexts[i].persistent);
+ VIR_FREE(fspoolInfoTexts[i].capacity);
+ VIR_FREE(fspoolInfoTexts[i].allocation);
+ VIR_FREE(fspoolInfoTexts[i].available);
+ }
+ }
+ VIR_FREE(fspoolInfoTexts);
+
+ virshFsPoolListFree(list);
+ return ret;
+}
+
+/*
+ * "fspool-info" command
+ */
+static const vshCmdInfo info_fspool_info[] = {
+ {.name = "help",
+ .data = N_("storage fspool information")
+ },
+ {.name = "desc",
+ .data = N_("Returns basic information about the storage fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_info[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolInfo(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolInfo info;
+ virFsPoolPtr fspool;
+ int autostart = 0;
+ int persistent = 0;
+ bool ret = true;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", NULL)))
+ return false;
+
+ vshPrint(ctl, "%-15s %s\n", _("Name:"),
virFsPoolGetName(fspool));
+
+ if (virFsPoolGetUUIDString(fspool, &uuid[0]) == 0)
+ vshPrint(ctl, "%-15s %s\n", _("UUID:"), uuid);
+
+ if (virFsPoolGetInfo(fspool, &info) == 0) {
+ double val;
+ const char *unit;
+ vshPrint(ctl, "%-15s %s\n", _("State:"),
+ virshFsPoolStateToString(info.state));
+
+ /* Check and display whether the fspool is persistent or not */
+ persistent = virFsPoolIsPersistent(fspool);
+ 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 fspool is autostarted or not */
+ if (virFsPoolGetAutostart(fspool, &autostart) < 0)
+ vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no
autostart"));
+ else
+ vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ?
_("yes") : _("no"));
+
+ if (info.state == VIR_FS_POOL_RUNNING) {
+ val = vshPrettyCapacity(info.capacity, &unit);
+ vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val,
unit);
+
+ val = vshPrettyCapacity(info.allocation, &unit);
+ vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val,
unit);
+
+ val = vshPrettyCapacity(info.available, &unit);
+ vshPrint(ctl, "%-15s %2.2lf %s\n", _("Available:"), val,
unit);
+ }
+ } else {
+ ret = false;
+ }
+
+ virFsPoolFree(fspool);
+ return ret;
+}
+
+/*
+ * "fspool-name" command
+ */
+static const vshCmdInfo info_fspool_name[] = {
+ {.name = "help",
+ .data = N_("convert a fspool UUID to fspool name")
+ },
+ {.name = "desc",
+ .data = ""
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_name[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolName(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+
+ if (!(fspool = virshCommandOptFsPoolBy(ctl, cmd, "fspool", NULL,
VIRSH_BYUUID)))
+ return false;
+
+ vshPrint(ctl, "%s\n", virFsPoolGetName(fspool));
+ virFsPoolFree(fspool);
+ return true;
+}
+
+/*
+ * "fspool-start" command
+ */
+static const vshCmdInfo info_fspool_start[] = {
+ {.name = "help",
+ .data = N_("start a (previously defined) inactive fspool")
+ },
+ {.name = "desc",
+ .data = N_("Start a fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_start[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+ VIRSH_COMMON_OPT_FS_POOL_BUILD,
+ VIRSH_COMMON_OPT_FS_POOL_NO_OVERWRITE,
+ VIRSH_COMMON_OPT_FS_POOL_OVERWRITE,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolStart(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ bool ret = true;
+ const char *name = NULL;
+ bool build;
+ bool overwrite;
+ bool no_overwrite;
+ unsigned int flags = 0;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name)))
+ return false;
+
+ build = vshCommandOptBool(cmd, "build");
+ overwrite = vshCommandOptBool(cmd, "overwrite");
+ no_overwrite = vshCommandOptBool(cmd, "no-overwrite");
+
+ VSH_EXCLUSIVE_OPTIONS_EXPR("overwrite", overwrite,
+ "no-overwrite", no_overwrite);
+
+ if (build)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD;
+ if (overwrite)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD_OVERWRITE;
+ if (no_overwrite)
+ flags |= VIR_FS_POOL_CREATE_WITH_BUILD_NO_OVERWRITE;
+
+ if (virFsPoolCreate(fspool, flags) == 0) {
+ vshPrint(ctl, _("Fspool %s started\n"), name);
+ } else {
+ vshError(ctl, _("Failed to start fspool %s"), name);
+ ret = false;
+ }
+
+ virFsPoolFree(fspool);
+ return ret;
+}
+
+/*
+ * "fspool-undefine" command
+ */
+static const vshCmdInfo info_fspool_undefine[] = {
+ {.name = "help",
+ .data = N_("undefine an inactive fspool")
+ },
+ {.name = "desc",
+ .data = N_("Undefine the configuration for an inactive fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_undefine[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolUndefine(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ bool ret = true;
+ const char *name;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", &name)))
+ return false;
+
+ if (virFsPoolUndefine(fspool) == 0) {
+ vshPrint(ctl, _("Pool %s has been undefined\n"), name);
+ } else {
+ vshError(ctl, _("Failed to undefine fspool %s"), name);
+ ret = false;
+ }
+
+ virFsPoolFree(fspool);
+ return ret;
+}
+
+/*
+ * "fspool-uuid" command
+ */
+static const vshCmdInfo info_fspool_uuid[] = {
+ {.name = "help",
+ .data = N_("convert a fspool name to fspool UUID")
+ },
+ {.name = "desc",
+ .data = ""
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_uuid[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolUuid(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+
+ if (!(fspool = virshCommandOptFsPoolBy(ctl, cmd, "fspool", NULL,
VIRSH_BYNAME)))
+ return false;
+
+ if (virFsPoolGetUUIDString(fspool, uuid) != -1)
+ vshPrint(ctl, "%s\n", uuid);
+ else
+ vshError(ctl, "%s", _("failed to get fspool UUID"));
+
+ virFsPoolFree(fspool);
+ return true;
+}
+
+/*
+ * "fspool-edit" command
+ */
+static const vshCmdInfo info_fspool_edit[] = {
+ {.name = "help",
+ .data = N_("edit XML configuration for a fspool")
+ },
+ {.name = "desc",
+ .data = N_("Edit the XML configuration for a fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_fspool_edit[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+
+ {.name = NULL}
+};
+
+static bool
+cmdFsPoolEdit(vshControl *ctl, const vshCmd *cmd)
+{
+ bool ret = false;
+ virFsPoolPtr fspool = NULL;
+ virFsPoolPtr fspool_edited = NULL;
+ unsigned int flags = VIR_FS_XML_INACTIVE;
+ char *tmp_desc = NULL;
+ virshControlPtr priv = ctl->privData;
+
+ fspool = virshCommandOptFsPool(ctl, cmd, "fspool", NULL);
+ if (fspool == NULL)
+ goto cleanup;
+
+ /* Some old daemons don't support _INACTIVE flag */
+ if (!(tmp_desc = virFsPoolGetXMLDesc(fspool, flags))) {
+ if (last_error->code == VIR_ERR_INVALID_ARG) {
+ flags &= ~VIR_FS_XML_INACTIVE;
+ vshResetLibvirtError();
+ } else {
+ goto cleanup;
+ }
+ } else {
+ VIR_FREE(tmp_desc);
+ }
+
+#define EDIT_GET_XML virFsPoolGetXMLDesc(fspool, flags)
+#define EDIT_NOT_CHANGED \
+ do { \
+ vshPrint(ctl, _("Pool %s XML configuration not changed.\n"), \
+ virFsPoolGetName(fspool)); \
+ ret = true; \
+ goto edit_cleanup; \
+ } while (0)
+#define EDIT_DEFINE \
+ (fspool_edited = virFsPoolDefineXML(priv->conn, doc_edited, 0))
+#include "virsh-edit.c"
+
+ vshPrint(ctl, _("Pool %s XML configuration edited.\n"),
+ virFsPoolGetName(fspool_edited));
+
+ ret = true;
+
+ cleanup:
+ if (fspool)
+ virFsPoolFree(fspool);
+ if (fspool_edited)
+ virFsPoolFree(fspool_edited);
+
+ return ret;
+}
+
+const vshCmdDef fsPoolCmds[] = {
+ {.name = "fspool-autostart",
+ .handler = cmdFsPoolAutostart,
+ .opts = opts_fspool_autostart,
+ .info = info_fspool_autostart,
+ .flags = 0
+ },
+ {.name = "fspool-build",
+ .handler = cmdFsPoolBuild,
+ .opts = opts_fspool_build,
+ .info = info_fspool_build,
+ .flags = 0
+ },
+ {.name = "fspool-create-as",
+ .handler = cmdFsPoolCreateAs,
+ .opts = opts_fspool_create_as,
+ .info = info_fspool_create_as,
+ .flags = 0
+ },
+ {.name = "fspool-create",
+ .handler = cmdFsPoolCreate,
+ .opts = opts_fspool_create,
+ .info = info_fspool_create,
+ .flags = 0
+ },
+ {.name = "fspool-define-as",
+ .handler = cmdFsPoolDefineAs,
+ .opts = opts_fspool_define_as,
+ .info = info_fspool_define_as,
+ .flags = 0
+ },
+ {.name = "fspool-define",
+ .handler = cmdFsPoolDefine,
+ .opts = opts_fspool_define,
+ .info = info_fspool_define,
+ .flags = 0
+ },
+ {.name = "fspool-delete",
+ .handler = cmdFsPoolDelete,
+ .opts = opts_fspool_delete,
+ .info = info_fspool_delete,
+ .flags = 0
+ },
+ {.name = "fspool-destroy",
+ .handler = cmdFsPoolDestroy,
+ .opts = opts_fspool_destroy,
+ .info = info_fspool_destroy,
+ .flags = 0
+ },
+ {.name = "fspool-dumpxml",
+ .handler = cmdFsPoolDumpXML,
+ .opts = opts_fspool_dumpxml,
+ .info = info_fspool_dumpxml,
+ .flags = 0
+ },
+ {.name = "fspool-edit",
+ .handler = cmdFsPoolEdit,
+ .opts = opts_fspool_edit,
+ .info = info_fspool_edit,
+ .flags = 0
+ },
+ {.name = "fspool-info",
+ .handler = cmdFsPoolInfo,
+ .opts = opts_fspool_info,
+ .info = info_fspool_info,
+ .flags = 0
+ },
+ {.name = "fspool-list",
+ .handler = cmdFsPoolList,
+ .opts = opts_fspool_list,
+ .info = info_fspool_list,
+ .flags = 0
+ },
+ {.name = "fspool-name",
+ .handler = cmdFsPoolName,
+ .opts = opts_fspool_name,
+ .info = info_fspool_name,
+ .flags = 0
+ },
+ {.name = "fspool-refresh",
+ .handler = cmdFsPoolRefresh,
+ .opts = opts_fspool_refresh,
+ .info = info_fspool_refresh,
+ .flags = 0
+ },
+ {.name = "fspool-undefine",
+ .handler = cmdFsPoolUndefine,
+ .opts = opts_fspool_undefine,
+ .info = info_fspool_undefine,
+ .flags = 0
+ },
+ {.name = "fspool-uuid",
+ .handler = cmdFsPoolUuid,
+ .opts = opts_fspool_uuid,
+ .info = info_fspool_uuid,
+ .flags = 0
+ },
+ {.name = "fspool-start",
+ .handler = cmdFsPoolStart,
+ .opts = opts_fspool_start,
+ .info = info_fspool_start,
+ .flags = 0
+ },
+ {.name = NULL}
+};
diff --git a/tools/virsh-fspool.h b/tools/virsh-fspool.h
new file mode 100644
index 0000000..d2d4361
--- /dev/null
+++ b/tools/virsh-fspool.h
@@ -0,0 +1,36 @@
+/*
+ * virsh-fspool.h: Commands to manage fspool
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VIRSH_FSPOOL_H
+# define VIRSH_FSPOOL_H
+
+# include "virsh.h"
+
+virFsPoolPtr
+virshCommandOptFsPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
+ const char **name, unsigned int flags);
+
+/* default is lookup by Name and UUID */
+# define virshCommandOptFsPool(_ctl, _cmd, _optname, _name) \
+ virshCommandOptFsPoolBy(_ctl, _cmd, _optname, _name, \
+ VIRSH_BYUUID | VIRSH_BYNAME)
+
+extern const vshCmdDef fsPoolCmds[];
+
+#endif /* VIRSH_FSPOOL_H */
diff --git a/tools/virsh-item.c b/tools/virsh-item.c
new file mode 100644
index 0000000..37c5c30
--- /dev/null
+++ b/tools/virsh-item.c
@@ -0,0 +1,1274 @@
+/*
+ * virsh-item.c: Commands to manage storage item
+ */
+
+#include <config.h>
+#include "virsh-item.h"
+
+#include <fcntl.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xmlsave.h>
+
+#include "internal.h"
+#include "virbuffer.h"
+#include "viralloc.h"
+#include "virutil.h"
+#include "virfile.h"
+#include "virsh-fspool.h"
+#include "virxml.h"
+#include "virstring.h"
+
+#define VIRSH_COMMON_OPT_FS_POOL_FULL \
+ VIRSH_COMMON_OPT_FS_POOL(N_("fspool name or uuid")) \
+
+#define VIRSH_COMMON_OPT_FS_POOL_NAME \
+ VIRSH_COMMON_OPT_FS_POOL(N_("fspool name")) \
+
+#define VIRSH_COMMON_OPT_FS_POOL_OPTIONAL \
+ {.name = "fspool", \
+ .type = VSH_OT_STRING, \
+ .help = N_("fspool name or uuid") \
+ } \
+
+#define VIRSH_COMMON_OPT_ITEM \
+ {.name = "item", \
+ .type = VSH_OT_DATA, \
+ .flags = VSH_OFLAG_REQ, \
+ .help = N_("item name, key or path") \
+ } \
+
+virFsItemPtr
+virshCommandOptItemBy(vshControl *ctl, const vshCmd *cmd,
+ const char *optname,
+ const char *fspooloptname,
+ const char **name, unsigned int flags)
+{
+ virFsItemPtr item = NULL;
+ virFsPoolPtr fspool = NULL;
+ const char *n = NULL, *p = NULL;
+ virshControlPtr priv = ctl->privData;
+
+ virCheckFlags(VIRSH_BYUUID | VIRSH_BYNAME, NULL);
+
+ if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
+ return NULL;
+
+ if (fspooloptname != NULL &&
+ vshCommandOptStringReq(ctl, cmd, fspooloptname, &p) < 0)
+ return NULL;
+
+ if (p) {
+ if (!(fspool = virshCommandOptFsPoolBy(ctl, cmd, fspooloptname, name, flags)))
+ return NULL;
+
+ if (virFsPoolIsActive(fspool) != 1) {
+ vshError(ctl, _("fspool '%s' is not active"), p);
+ virFsPoolFree(fspool);
+ return NULL;
+ }
+ }
+
+ 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 (fspool && (flags & VIRSH_BYNAME)) {
+ vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as item name\n",
+ cmd->def->name, optname);
+ item = virFsItemLookupByName(fspool, n);
+ }
+ /* try it by key */
+ if (!item && (flags & VIRSH_BYUUID)) {
+ vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as item key\n",
+ cmd->def->name, optname);
+ item = virFsItemLookupByKey(priv->conn, n);
+ }
+ /* try it by path */
+ if (!item && (flags & VIRSH_BYUUID)) {
+ vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as item path\n",
+ cmd->def->name, optname);
+ item = virFsItemLookupByPath(priv->conn, n);
+ }
+
+ if (!item) {
+ if (fspool || !fspooloptname)
+ vshError(ctl, _("failed to get item '%s'"), n);
+ else
+ vshError(ctl, _("failed to get item '%s', specifying --%s
"
+ "might help"), n, fspooloptname);
+ }
+
+ /* If the fspool was specified, then make sure that the returned
+ * item is from the given fspool */
+ if (fspool && item) {
+ virFsPoolPtr itemfspool = NULL;
+
+ if ((itemfspool = virFsPoolLookupByItem(item))) {
+ if (STRNEQ(virFsPoolGetName(itemfspool),
+ virFsPoolGetName(fspool))) {
+ vshResetLibvirtError();
+ vshError(ctl,
+ _("Requested item '%s' is not in fspool
'%s'"),
+ n, virFsPoolGetName(fspool));
+ virFsItemFree(item);
+ item = NULL;
+ }
+ virFsPoolFree(itemfspool);
+ }
+ }
+
+ if (fspool)
+ virFsPoolFree(fspool);
+
+ return item;
+}
+
+/*
+ * "item-create-as" command
+ */
+static const vshCmdInfo info_item_create_as[] = {
+ {.name = "help",
+ .data = N_("create a item from a set of args")
+ },
+ {.name = "desc",
+ .data = N_("Create a item.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_create_as[] = {
+ VIRSH_COMMON_OPT_FS_POOL_NAME,
+ {.name = "name",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("name of the item")
+ },
+ {.name = "capacity",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("size of the item, as scaled integer (default bytes)")
+ },
+ {.name = "allocation",
+ .type = VSH_OT_STRING,
+ .help = N_("initial allocation size, as scaled integer (default bytes)")
+ },
+ {.name = "format",
+ .type = VSH_OT_STRING,
+ .help = N_("file format type raw,bochs,qcow,qcow2,qed,vmdk")
+ },
+ {.name = "print-xml",
+ .type = VSH_OT_BOOL,
+ .help = N_("print XML document, but don't define/create")
+ },
+ {.name = NULL}
+};
+
+static int
+virshItemSize(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
+cmdItemCreateAs(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ virFsItemPtr item = NULL;
+ char *xml = NULL;
+ bool printXML = vshCommandOptBool(cmd, "print-xml");
+ const char *name, *capacityStr = NULL, *allocationStr = NULL, *format = NULL;
+ unsigned long long capacity, allocation = 0;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ unsigned long flags = 0;
+ bool ret = false;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", NULL)))
+ return false;
+
+ if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
+ goto cleanup;
+
+ if (vshCommandOptStringReq(ctl, cmd, "capacity", &capacityStr) < 0)
+ goto cleanup;
+
+ if (virshItemSize(capacityStr, &capacity) < 0) {
+ vshError(ctl, _("Malformed size %s"), capacityStr);
+ goto cleanup;
+ }
+
+ if (vshCommandOptStringQuiet(ctl, cmd, "allocation", &allocationStr)
> 0 &&
+ virshItemSize(allocationStr, &allocation) < 0) {
+ vshError(ctl, _("Malformed size %s"), allocationStr);
+ goto cleanup;
+ }
+
+ if (vshCommandOptStringReq(ctl, cmd, "format", &format))
+ goto cleanup;
+
+ virBufferAddLit(&buf, "<item>\n");
+ virBufferAdjustIndent(&buf, 2);
+ virBufferAsprintf(&buf, "<name>%s</name>\n", name);
+ virBufferAsprintf(&buf, "<capacity>%llu</capacity>\n",
capacity);
+ if (allocationStr)
+ virBufferAsprintf(&buf,
"<allocation>%llu</allocation>\n", allocation);
+
+ if (format) {
+ virBufferAddLit(&buf, "<target>\n");
+ virBufferAdjustIndent(&buf, 2);
+ virBufferAsprintf(&buf, "<format type='%s'/>\n",
format);
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</target>\n");
+ }
+
+ virBufferAdjustIndent(&buf, -2);
+ virBufferAddLit(&buf, "</item>\n");
+
+ if (virBufferError(&buf)) {
+ vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
+ goto cleanup;
+ }
+ xml = virBufferContentAndReset(&buf);
+
+ if (printXML) {
+ vshPrint(ctl, "%s", xml);
+ } else {
+ if (!(item = virFsItemCreateXML(fspool, xml, flags))) {
+ vshError(ctl, _("Failed to create item %s"), name);
+ goto cleanup;
+ }
+ vshPrint(ctl, _("Item %s created\n"), name);
+ }
+
+ ret = true;
+
+ cleanup:
+ virBufferFreeAndReset(&buf);
+ if (item)
+ virFsItemFree(item);
+ virFsPoolFree(fspool);
+ VIR_FREE(xml);
+ return ret;
+}
+
+/*
+ * "item-create" command
+ */
+static const vshCmdInfo info_item_create[] = {
+ {.name = "help",
+ .data = N_("create a item from an XML file")
+ },
+ {.name = "desc",
+ .data = N_("Create a item.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_create[] = {
+ VIRSH_COMMON_OPT_FS_POOL_NAME,
+ VIRSH_COMMON_OPT_FILE(N_("file containing an XML item description")),
+ {.name = NULL}
+};
+
+static bool
+cmdItemCreate(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ virFsItemPtr item;
+ const char *from = NULL;
+ bool ret = false;
+ unsigned int flags = 0;
+ char *buffer = NULL;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", NULL)))
+ return false;
+
+ if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
+ goto cleanup;
+
+ if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
+ vshSaveLibvirtError();
+ goto cleanup;
+ }
+
+ if ((item = virFsItemCreateXML(fspool, buffer, flags))) {
+ vshPrint(ctl, _("Item %s created from %s\n"),
+ virFsItemGetName(item), from);
+ virFsItemFree(item);
+ ret = true;
+ } else {
+ vshError(ctl, _("Failed to create item from %s"), from);
+ }
+
+ cleanup:
+ VIR_FREE(buffer);
+ virFsPoolFree(fspool);
+ return ret;
+}
+
+/*
+ * "item-create-from" command
+ */
+static const vshCmdInfo info_item_create_from[] = {
+ {.name = "help",
+ .data = N_("create a item, using another item as input")
+ },
+ {.name = "desc",
+ .data = N_("Create a item from an existing item.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_create_from[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+ VIRSH_COMMON_OPT_FILE(N_("file containing an XML item description")),
+ VIRSH_COMMON_OPT_ITEM,
+ {.name = "inputfspool",
+ .type = VSH_OT_STRING,
+ .help = N_("fspool name or uuid of the input item's fspool")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdItemCreateFrom(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool = NULL;
+ virFsItemPtr newitem = NULL, inputitem = NULL;
+ const char *from = NULL;
+ bool ret = false;
+ char *buffer = NULL;
+ unsigned int flags = 0;
+
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", NULL)))
+ goto cleanup;
+
+ if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
+ goto cleanup;
+
+ if (!(inputitem = virshCommandOptItem(ctl, cmd, "item",
"inputfspool", NULL)))
+ goto cleanup;
+
+ if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0) {
+ vshReportError(ctl);
+ goto cleanup;
+ }
+
+ newitem = virFsItemCreateXMLFrom(fspool, buffer, inputitem, flags);
+
+ if (newitem != NULL) {
+ vshPrint(ctl, _("Item %s created from input item %s\n"),
+ virFsItemGetName(newitem), virFsItemGetName(inputitem));
+ } else {
+ vshError(ctl, _("Failed to create item from %s"), from);
+ goto cleanup;
+ }
+
+ ret = true;
+ cleanup:
+ VIR_FREE(buffer);
+ if (fspool)
+ virFsPoolFree(fspool);
+ if (inputitem)
+ virFsItemFree(inputitem);
+ if (newitem)
+ virFsItemFree(newitem);
+ return ret;
+}
+
+static xmlChar *
+virshMakeCloneXML(const char *origxml, const char *newname)
+{
+
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctxt = NULL;
+ xmlXPathObjectPtr obj = NULL;
+ xmlChar *newxml = NULL;
+ int size;
+
+ doc = virXMLParseStringCtxt(origxml, _("(item_definition)"), &ctxt);
+ if (!doc)
+ goto cleanup;
+
+ obj = xmlXPathEval(BAD_CAST "/item/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;
+}
+
+/*
+ * "item-clone" command
+ */
+static const vshCmdInfo info_item_clone[] = {
+ {.name = "help",
+ .data = N_("clone a item.")
+ },
+ {.name = "desc",
+ .data = N_("Clone an existing item within the parent fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_clone[] = {
+ VIRSH_COMMON_OPT_ITEM,
+ {.name = "newname",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("clone name")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdItemClone(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr origfspool = NULL;
+ virFsItemPtr origitem = NULL, newitem = NULL;
+ const char *name = NULL;
+ char *origxml = NULL;
+ xmlChar *newxml = NULL;
+ bool ret = false;
+ unsigned int flags = 0;
+
+ if (!(origitem = virshCommandOptItem(ctl, cmd, "item", "fspool",
NULL)))
+ goto cleanup;
+
+ origfspool = virFsPoolLookupByItem(origitem);
+ if (!origfspool) {
+ vshError(ctl, "%s", _("failed to get parent fspool"));
+ goto cleanup;
+ }
+
+ if (vshCommandOptStringReq(ctl, cmd, "newname", &name) < 0)
+ goto cleanup;
+
+ origxml = virFsItemGetXMLDesc(origitem, 0);
+ if (!origxml)
+ goto cleanup;
+
+ newxml = virshMakeCloneXML(origxml, name);
+ if (!newxml) {
+ vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
+ goto cleanup;
+ }
+
+ newitem = virFsItemCreateXMLFrom(origfspool, (char *) newxml, origitem, flags);
+
+ if (newitem != NULL) {
+ vshPrint(ctl, _("Item %s cloned from %s\n"),
+ virFsItemGetName(newitem), virFsItemGetName(origitem));
+ } else {
+ vshError(ctl, _("Failed to clone item from %s"),
+ virFsItemGetName(origitem));
+ goto cleanup;
+ }
+
+ ret = true;
+
+ cleanup:
+ VIR_FREE(origxml);
+ xmlFree(newxml);
+ if (origitem)
+ virFsItemFree(origitem);
+ if (newitem)
+ virFsItemFree(newitem);
+ if (origfspool)
+ virFsPoolFree(origfspool);
+ return ret;
+}
+
+/*
+ * "item-delete" command
+ */
+static const vshCmdInfo info_item_delete[] = {
+ {.name = "help",
+ .data = N_("delete a item")
+ },
+ {.name = "desc",
+ .data = N_("Delete a given item.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_delete[] = {
+ VIRSH_COMMON_OPT_ITEM,
+ VIRSH_COMMON_OPT_FS_POOL_OPTIONAL,
+ {.name = NULL}
+};
+
+static bool
+cmdItemDelete(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsItemPtr item;
+ bool ret = true;
+ const char *name;
+ unsigned int flags = 0;
+
+ if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool",
&name)))
+ return false;
+
+ if (virFsItemDelete(item, flags) == 0) {
+ vshPrint(ctl, _("Item %s deleted\n"), name);
+ } else {
+ vshError(ctl, _("Failed to delete item %s"), name);
+ ret = false;
+ }
+
+ virFsItemFree(item);
+ return ret;
+}
+
+VIR_ENUM_DECL(virshFsItem)
+VIR_ENUM_IMPL(virshFsItem,
+ VIR_FS_ITEM_LAST,
+ N_("dir"))
+
+static const char *
+virshItemTypeToString(int type)
+{
+ const char *str = virshFsItemTypeToString(type);
+ return str ? _(str) : _("unknown");
+}
+
+
+/*
+ * "item-info" command
+ */
+static const vshCmdInfo info_item_info[] = {
+ {.name = "help",
+ .data = N_("storage item information")
+ },
+ {.name = "desc",
+ .data = N_("Returns basic information about the storage item.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_info[] = {
+ VIRSH_COMMON_OPT_ITEM,
+ VIRSH_COMMON_OPT_FS_POOL_OPTIONAL,
+ {.name = "bytes",
+ .type = VSH_OT_BOOL,
+ .help = N_("sizes are represented in bytes rather than pretty units")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdItemInfo(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsItemInfo info;
+ virFsItemPtr item;
+ bool bytes = vshCommandOptBool(cmd, "bytes");
+ bool ret = true;
+
+ if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool",
NULL)))
+ return false;
+
+ vshPrint(ctl, "%-15s %s\n", _("Name:"), virFsItemGetName(item));
+
+ if (virFsItemGetInfo(item, &info) == 0) {
+ double val;
+ const char *unit;
+
+ vshPrint(ctl, "%-15s %s\n", _("Type:"),
+ virshItemTypeToString(info.type));
+
+ if (bytes) {
+ vshPrint(ctl, "%-15s %llu %s\n", _("Capacity:"),
+ info.capacity, _("bytes"));
+ } else {
+ val = vshPrettyCapacity(info.capacity, &unit);
+ vshPrint(ctl, "%-15s %2.2lf %s\n", _("Capacity:"), val,
unit);
+ }
+
+ if (bytes) {
+ vshPrint(ctl, "%-15s %llu %s\n", _("Allocation:"),
+ info.allocation, _("bytes"));
+ } else {
+ val = vshPrettyCapacity(info.allocation, &unit);
+ vshPrint(ctl, "%-15s %2.2lf %s\n", _("Allocation:"), val,
unit);
+ }
+ } else {
+ ret = false;
+ }
+
+ virFsItemFree(item);
+ return ret;
+}
+
+/*
+ * "item-dumpxml" command
+ */
+static const vshCmdInfo info_item_dumpxml[] = {
+ {.name = "help",
+ .data = N_("item information in XML")
+ },
+ {.name = "desc",
+ .data = N_("Output the item information as an XML dump to stdout.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_dumpxml[] = {
+ VIRSH_COMMON_OPT_ITEM,
+ VIRSH_COMMON_OPT_FS_POOL_OPTIONAL,
+ {.name = NULL}
+};
+
+static bool
+cmdItemDumpXML(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsItemPtr item;
+ bool ret = true;
+ char *dump;
+
+ if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool",
NULL)))
+ return false;
+
+ dump = virFsItemGetXMLDesc(item, 0);
+ if (dump != NULL) {
+ vshPrint(ctl, "%s", dump);
+ VIR_FREE(dump);
+ } else {
+ ret = false;
+ }
+
+ virFsItemFree(item);
+ return ret;
+}
+
+static int
+virshFsItemSorter(const void *a, const void *b)
+{
+ virFsItemPtr *va = (virFsItemPtr *) a;
+ virFsItemPtr *vb = (virFsItemPtr *) b;
+
+ if (*va && !*vb)
+ return -1;
+
+ if (!*va)
+ return *vb != NULL;
+
+ return vshStrcasecmp(virFsItemGetName(*va),
+ virFsItemGetName(*vb));
+}
+
+struct virshFsItemList {
+ virFsItemPtr *items;
+ size_t nitems;
+};
+typedef struct virshFsItemList *virshFsItemListPtr;
+
+static void
+virshFsItemListFree(virshFsItemListPtr list)
+{
+ size_t i;
+
+ if (list && list->items) {
+ for (i = 0; i < list->nitems; i++) {
+ if (list->items[i])
+ virFsItemFree(list->items[i]);
+ }
+ VIR_FREE(list->items);
+ }
+ VIR_FREE(list);
+}
+
+static virshFsItemListPtr
+virshFsItemListCollect(vshControl *ctl,
+ virFsPoolPtr fspool,
+ unsigned int flags)
+{
+ virshFsItemListPtr list = vshMalloc(ctl, sizeof(*list));
+ size_t i;
+ char **names = NULL;
+ virFsItemPtr item = NULL;
+ bool success = false;
+ size_t deleted = 0;
+ int nitems = 0;
+ int ret = -1;
+
+ /* try the list with flags support (0.10.2 and later) */
+ if ((ret = virFsPoolListAllItems(fspool,
+ &list->items,
+ flags)) >= 0) {
+ list->nitems = ret;
+ goto finished;
+ }
+
+ /* check if the command is actually supported */
+ if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
+ goto fallback;
+
+ /* there was an error during the call */
+ vshError(ctl, "%s", _("Failed to list items"));
+ goto cleanup;
+
+ fallback:
+ /* fall back to old method (0.10.1 and older) */
+ vshResetLibvirtError();
+
+ /* Determine the number of items in the fspool */
+ if ((nitems = virFsPoolNumOfItems(fspool)) < 0) {
+ vshError(ctl, "%s", _("Failed to list storage items"));
+ goto cleanup;
+ }
+
+ if (nitems == 0) {
+ success = true;
+ return list;
+ }
+
+ /* Retrieve the list of item names in the fspool */
+ names = vshCalloc(ctl, nitems, sizeof(*names));
+ if ((nitems = virFsPoolListItems(fspool, names, nitems)) < 0) {
+ vshError(ctl, "%s", _("Failed to list storage items"));
+ goto cleanup;
+ }
+
+ list->items = vshMalloc(ctl, sizeof(virFsItemPtr) * (nitems));
+ list->nitems = 0;
+
+ /* get the items */
+ for (i = 0; i < nitems; i++) {
+ if (!(item = virFsItemLookupByName(fspool, names[i])))
+ continue;
+ list->items[list->nitems++] = item;
+ }
+
+ /* truncate the list for not found items */
+ deleted = nitems - list->nitems;
+
+ finished:
+ /* sort the list */
+ if (list->items && list->nitems)
+ qsort(list->items, list->nitems, sizeof(*list->items),
virshFsItemSorter);
+
+ if (deleted)
+ VIR_SHRINK_N(list->items, list->nitems, deleted);
+
+ success = true;
+
+ cleanup:
+ if (nitems > 0)
+ for (i = 0; i < nitems; i++)
+ VIR_FREE(names[i]);
+ VIR_FREE(names);
+
+ if (!success) {
+ virshFsItemListFree(list);
+ list = NULL;
+ }
+
+ return list;
+}
+
+/*
+ * "item-list" command
+ */
+static const vshCmdInfo info_item_list[] = {
+ {.name = "help",
+ .data = N_("list items")
+ },
+ {.name = "desc",
+ .data = N_("Returns list of items by fspool.")
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_list[] = {
+ VIRSH_COMMON_OPT_FS_POOL_FULL,
+ {.name = "details",
+ .type = VSH_OT_BOOL,
+ .help = N_("display extended details for items")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdItemList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+ virFsItemInfo itemInfo;
+ virFsPoolPtr fspool;
+ char *outputStr = NULL;
+ const char *unit;
+ double val;
+ bool details = vshCommandOptBool(cmd, "details");
+ size_t i;
+ bool ret = false;
+ int stringLength = 0;
+ size_t allocStrLength = 0, capStrLength = 0;
+ size_t nameStrLength = 0, pathStrLength = 0;
+ size_t typeStrLength = 0;
+ struct itemInfoText {
+ char *allocation;
+ char *capacity;
+ char *path;
+ char *type;
+ };
+ struct itemInfoText *itemInfoTexts = NULL;
+ virshFsItemListPtr list = NULL;
+
+ /* Look up the fspool information given to us by the user */
+ if (!(fspool = virshCommandOptFsPool(ctl, cmd, "fspool", NULL)))
+ return false;
+
+ if (!(list = virshFsItemListCollect(ctl, fspool, 0)))
+ goto cleanup;
+
+ if (list->nitems > 0)
+ itemInfoTexts = vshCalloc(ctl, list->nitems, sizeof(*itemInfoTexts));
+
+ /* Collect the rest of the item information for display */
+ for (i = 0; i < list->nitems; i++) {
+ /* Retrieve item info */
+ virFsItemPtr item = list->items[i];
+
+ /* Retrieve the item path */
+ if ((itemInfoTexts[i].path = virFsItemGetPath(item)) == NULL) {
+ /* Something went wrong retrieving a item path, cope with it */
+ itemInfoTexts[i].path = vshStrdup(ctl, _("unknown"));
+ }
+
+ /* If requested, retrieve item type and sizing information */
+ if (details) {
+ if (virFsItemGetInfo(item, &itemInfo) != 0) {
+ /* Something went wrong retrieving item info, cope with it */
+ itemInfoTexts[i].allocation = vshStrdup(ctl, _("unknown"));
+ itemInfoTexts[i].capacity = vshStrdup(ctl, _("unknown"));
+ itemInfoTexts[i].type = vshStrdup(ctl, _("unknown"));
+ } else {
+ /* Convert the returned item info into output strings */
+
+ /* Item type */
+ itemInfoTexts[i].type = vshStrdup(ctl,
+ virshItemTypeToString(itemInfo.type));
+
+ val = vshPrettyCapacity(itemInfo.capacity, &unit);
+ if (virAsprintf(&itemInfoTexts[i].capacity,
+ "%.2lf %s", val, unit) < 0)
+ goto cleanup;
+
+ val = vshPrettyCapacity(itemInfo.allocation, &unit);
+ if (virAsprintf(&itemInfoTexts[i].allocation,
+ "%.2lf %s", val, unit) < 0)
+ goto cleanup;
+ }
+
+ /* Remember the largest length for each output string.
+ * This lets us displaying header and item information rows
+ * using a single, properly sized, printf style output string.
+ */
+
+ /* Keep the length of name string if longest so far */
+ stringLength = strlen(virFsItemGetName(list->items[i]));
+ if (stringLength > nameStrLength)
+ nameStrLength = stringLength;
+
+ /* Keep the length of path string if longest so far */
+ stringLength = strlen(itemInfoTexts[i].path);
+ if (stringLength > pathStrLength)
+ pathStrLength = stringLength;
+
+ /* Keep the length of type string if longest so far */
+ stringLength = strlen(itemInfoTexts[i].type);
+ if (stringLength > typeStrLength)
+ typeStrLength = stringLength;
+
+ /* Keep the length of capacity string if longest so far */
+ stringLength = strlen(itemInfoTexts[i].capacity);
+ if (stringLength > capStrLength)
+ capStrLength = stringLength;
+
+ /* Keep the length of allocation string if longest so far */
+ stringLength = strlen(itemInfoTexts[i].allocation);
+ if (stringLength > allocStrLength)
+ allocStrLength = stringLength;
+ }
+ }
+
+ /* If the --details option wasn't selected, we output the item
+ * 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 < list->nitems; i++) {
+ vshPrint(ctl, " %-20s %-40s\n",
virFsItemGetName(list->items[i]),
+ itemInfoTexts[i].path);
+ }
+
+ /* Cleanup and return */
+ ret = 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);
+
+ if (virAsprintf(&outputStr,
+ " %%-%lus %%-%lus %%-%lus %%%lus %%%lus\n",
+ (unsigned long) nameStrLength,
+ (unsigned long) pathStrLength,
+ (unsigned long) typeStrLength,
+ (unsigned long) capStrLength,
+ (unsigned long) allocStrLength) < 0)
+ goto cleanup;
+
+ /* Display the header */
+ vshPrint(ctl, outputStr, _("Name"), _("Path"),
_("Type"),
+ ("Capacity"), _("Allocation"));
+ for (i = nameStrLength + pathStrLength + typeStrLength
+ + capStrLength + allocStrLength
+ + 10; i > 0; i--)
+ vshPrintExtra(ctl, "-");
+ vshPrintExtra(ctl, "\n");
+
+ /* Display the item info rows */
+ for (i = 0; i < list->nitems; i++) {
+ vshPrint(ctl, outputStr,
+ virFsItemGetName(list->items[i]),
+ itemInfoTexts[i].path,
+ itemInfoTexts[i].type,
+ itemInfoTexts[i].capacity,
+ itemInfoTexts[i].allocation);
+ }
+
+ /* Cleanup and return */
+ ret = true;
+
+ cleanup:
+
+ /* Safely free the memory allocated in this function */
+ if (list && list->nitems) {
+ for (i = 0; i < list->nitems; i++) {
+ /* Cleanup the memory for one item info structure per loop */
+ VIR_FREE(itemInfoTexts[i].path);
+ VIR_FREE(itemInfoTexts[i].type);
+ VIR_FREE(itemInfoTexts[i].capacity);
+ VIR_FREE(itemInfoTexts[i].allocation);
+ }
+ }
+
+ /* Cleanup remaining memory */
+ VIR_FREE(outputStr);
+ VIR_FREE(itemInfoTexts);
+ virFsPoolFree(fspool);
+ virshFsItemListFree(list);
+
+ /* Return the desired value */
+ return ret;
+}
+
+/*
+ * "item-name" command
+ */
+static const vshCmdInfo info_item_name[] = {
+ {.name = "help",
+ .data = N_("returns the item name for a given item key or path")
+ },
+ {.name = "desc",
+ .data = ""
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_name[] = {
+ {.name = "item",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("item key or path")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdItemName(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsItemPtr item;
+
+ if (!(item = virshCommandOptItemBy(ctl, cmd, "item", NULL, NULL,
+ VIRSH_BYUUID)))
+ return false;
+
+ vshPrint(ctl, "%s\n", virFsItemGetName(item));
+ virFsItemFree(item);
+ return true;
+}
+
+/*
+ * "item-fspool" command
+ */
+static const vshCmdInfo info_item_fspool[] = {
+ {.name = "help",
+ .data = N_("returns the storage fspool for a given item key or path")
+ },
+ {.name = "desc",
+ .data = ""
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_fspool[] = {
+ {.name = "item",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("item key or path")
+ },
+ {.name = "uuid",
+ .type = VSH_OT_BOOL,
+ .help = N_("return the fspool uuid rather than fspool name")
+ },
+ {.name = NULL}
+};
+
+static bool
+cmdItemPool(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsPoolPtr fspool;
+ virFsItemPtr item;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+
+ /* Use the supplied string to locate the item */
+ if (!(item = virshCommandOptItemBy(ctl, cmd, "item", NULL, NULL,
+ VIRSH_BYUUID))) {
+ return false;
+ }
+
+ /* Look up the parent storage fspool for the item */
+ fspool = virFsPoolLookupByItem(item);
+ if (fspool == NULL) {
+ vshError(ctl, "%s", _("failed to get parent fspool"));
+ virFsItemFree(item);
+ return false;
+ }
+
+ /* Return the requested details of the parent storage fspool */
+ if (vshCommandOptBool(cmd, "uuid")) {
+ /* Retrieve and return fspool UUID string */
+ if (virFsPoolGetUUIDString(fspool, &uuid[0]) == 0)
+ vshPrint(ctl, "%s\n", uuid);
+ } else {
+ /* Return the storage fspool name */
+ vshPrint(ctl, "%s\n", virFsPoolGetName(fspool));
+ }
+
+ /* Cleanup */
+ virFsItemFree(item);
+ virFsPoolFree(fspool);
+ return true;
+}
+
+/*
+ * "item-key" command
+ */
+static const vshCmdInfo info_item_key[] = {
+ {.name = "help",
+ .data = N_("returns the item key for a given item name or path")
+ },
+ {.name = "desc",
+ .data = ""
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_key[] = {
+ {.name = "item",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("item name or path")
+ },
+ VIRSH_COMMON_OPT_FS_POOL_OPTIONAL,
+ {.name = NULL}
+};
+
+static bool
+cmdItemKey(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsItemPtr item;
+
+ if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool",
NULL)))
+ return false;
+
+ vshPrint(ctl, "%s\n", virFsItemGetKey(item));
+ virFsItemFree(item);
+ return true;
+}
+
+/*
+ * "item-path" command
+ */
+static const vshCmdInfo info_item_path[] = {
+ {.name = "help",
+ .data = N_("returns the item path for a given item name or key")
+ },
+ {.name = "desc",
+ .data = ""
+ },
+ {.name = NULL}
+};
+
+static const vshCmdOptDef opts_item_path[] = {
+ {.name = "item",
+ .type = VSH_OT_DATA,
+ .flags = VSH_OFLAG_REQ,
+ .help = N_("item name or key")
+ },
+ VIRSH_COMMON_OPT_FS_POOL_OPTIONAL,
+ {.name = NULL}
+};
+
+static bool
+cmdItemPath(vshControl *ctl, const vshCmd *cmd)
+{
+ virFsItemPtr item;
+ char * FsItemPath;
+
+ if (!(item = virshCommandOptItem(ctl, cmd, "item", "fspool",
NULL)))
+ return false;
+
+ if ((FsItemPath = virFsItemGetPath(item)) == NULL) {
+ virFsItemFree(item);
+ return false;
+ }
+
+ vshPrint(ctl, "%s\n", FsItemPath);
+ VIR_FREE(FsItemPath);
+ virFsItemFree(item);
+ return true;
+}
+
+const vshCmdDef fsItemCmds[] = {
+ {.name = "item-clone",
+ .handler = cmdItemClone,
+ .opts = opts_item_clone,
+ .info = info_item_clone,
+ .flags = 0
+ },
+ {.name = "item-create-as",
+ .handler = cmdItemCreateAs,
+ .opts = opts_item_create_as,
+ .info = info_item_create_as,
+ .flags = 0
+ },
+ {.name = "item-create",
+ .handler = cmdItemCreate,
+ .opts = opts_item_create,
+ .info = info_item_create,
+ .flags = 0
+ },
+ {.name = "item-create-from",
+ .handler = cmdItemCreateFrom,
+ .opts = opts_item_create_from,
+ .info = info_item_create_from,
+ .flags = 0
+ },
+ {.name = "item-delete",
+ .handler = cmdItemDelete,
+ .opts = opts_item_delete,
+ .info = info_item_delete,
+ .flags = 0
+ },
+ {.name = "item-dumpxml",
+ .handler = cmdItemDumpXML,
+ .opts = opts_item_dumpxml,
+ .info = info_item_dumpxml,
+ .flags = 0
+ },
+ {.name = "item-info",
+ .handler = cmdItemInfo,
+ .opts = opts_item_info,
+ .info = info_item_info,
+ .flags = 0
+ },
+ {.name = "item-key",
+ .handler = cmdItemKey,
+ .opts = opts_item_key,
+ .info = info_item_key,
+ .flags = 0
+ },
+ {.name = "item-list",
+ .handler = cmdItemList,
+ .opts = opts_item_list,
+ .info = info_item_list,
+ .flags = 0
+ },
+ {.name = "item-name",
+ .handler = cmdItemName,
+ .opts = opts_item_name,
+ .info = info_item_name,
+ .flags = 0
+ },
+ {.name = "item-path",
+ .handler = cmdItemPath,
+ .opts = opts_item_path,
+ .info = info_item_path,
+ .flags = 0
+ },
+ {.name = "item-fspool",
+ .handler = cmdItemPool,
+ .opts = opts_item_fspool,
+ .info = info_item_fspool,
+ .flags = 0
+ },
+ {.name = NULL}
+};
diff --git a/tools/virsh-item.h b/tools/virsh-item.h
new file mode 100644
index 0000000..841ff43
--- /dev/null
+++ b/tools/virsh-item.h
@@ -0,0 +1,37 @@
+/*
+ * virsh-item.h: Commands to manage fsitems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef VIRSH_ITEM_H
+# define VIRSH_ITEM_H
+
+# include "virsh.h"
+
+virFsItemPtr virshCommandOptItemBy(vshControl *ctl, const vshCmd *cmd,
+ const char *optname,
+ const char *fspooloptname,
+ const char **name, unsigned int flags);
+
+/* default is lookup by Name and UUID */
+# define virshCommandOptItem(_ctl, _cmd, _optname, _fspooloptname, _name) \
+ virshCommandOptItemBy(_ctl, _cmd, _optname, _fspooloptname, _name, \
+ VIRSH_BYUUID | VIRSH_BYNAME)
+
+extern const vshCmdDef fsItemCmds[];
+
+#endif /* VIRSH_ITEM_H */
diff --git a/tools/virsh.c b/tools/virsh.c
index d3fe06f..35c82c6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -68,9 +68,11 @@
#include "virsh-nodedev.h"
#include "virsh-nwfilter.h"
#include "virsh-pool.h"
+#include "virsh-fspool.h"
#include "virsh-secret.h"
#include "virsh-snapshot.h"
#include "virsh-volume.h"
+#include "virsh-item.h"
/* Gnulib doesn't guarantee SA_SIGINFO support. */
#ifndef SA_SIGINFO
@@ -921,6 +923,8 @@ static const vshCmdGrp cmdGroups[] = {
{VIRSH_CMD_GRP_SNAPSHOT, "snapshot", snapshotCmds},
{VIRSH_CMD_GRP_STORAGE_POOL, "pool", storagePoolCmds},
{VIRSH_CMD_GRP_STORAGE_VOL, "volume", storageVolCmds},
+ {VIRSH_CMD_GRP_FS_POOL, "fspool", fsPoolCmds},
+ {VIRSH_CMD_GRP_FS_ITEM, "item", fsItemCmds},
{VIRSH_CMD_GRP_VIRSH, "virsh", virshCmds},
{NULL, NULL, NULL}
};
diff --git a/tools/virsh.h b/tools/virsh.h
index fd552bb..b1a1d0d 100644
--- a/tools/virsh.h
+++ b/tools/virsh.h
@@ -51,6 +51,8 @@
# define VIRSH_CMD_GRP_DOM_MONITORING "Domain Monitoring"
# define VIRSH_CMD_GRP_STORAGE_POOL "Storage Pool"
# define VIRSH_CMD_GRP_STORAGE_VOL "Storage Volume"
+# define VIRSH_CMD_GRP_FS_POOL "Fspool"
+# define VIRSH_CMD_GRP_FS_ITEM "Item"
# define VIRSH_CMD_GRP_NETWORK "Networking"
# define VIRSH_CMD_GRP_NODEDEV "Node Device"
# define VIRSH_CMD_GRP_IFACE "Interface"
@@ -70,6 +72,13 @@
.help = _helpstr \
} \
+# define VIRSH_COMMON_OPT_FS_POOL(_helpstr) \
+ {.name = "fspool", \
+ .type = VSH_OT_DATA, \
+ .flags = VSH_OFLAG_REQ, \
+ .help = _helpstr \
+ }
+
# define VIRSH_COMMON_OPT_DOMAIN(_helpstr) \
{.name = "domain", \
.type = VSH_OT_DATA, \
--
1.8.3.1