Everyone[1] seems to be doing funky bash auto-completion for commands these
days, so I thought I'd make a stab at doing something for virsh.
First of all I needed the command line help in an easier format to deal
with, so I've added
virsh _complete-command commands|arguments|options
eg,
$ virsh _complete-command commands
help
attach-device
attach-disk
attach-interface
autostart
capabilities
connect
console
...snip rest...
$ virsh _complete-command arguments vcpupin
domain
vcpu
cpulist
$ virsh _complete-command options
-c
--connect
-r
--readonly
-d
--debug
-h
--help
-q
--quiet
-t
--timing
-l
--log
-v
--version
$ virsh _complete-command options net-list
--inactive
--all
That's enough to get all the basic commands & options auto-completing.
For the arguments though I wanted to be able to auto-complete domain
names, ids and UUIDs. likewise for storage pools and networks. I also
wanted to auto-complete connect URIs ,eg test://default, qemu:///system
$ virsh _complete-domain
ISCSIServer
35e5efcc-f6a3-b489-fc33-99f2e4792e6d
untangle
dc502cb8-4bdd-7a15-f35a-cf76287ea2bd
VirtTest
82038f2a-1344-aaf7-1a85-2a7250be2076
xenner
18c23d31-4d74-0bff-986d-e4251d2a2ff0
And
$ virsh _complete-uri
test:///default
qemu:///system
lxc:///
For this latter command, I needed to add a new API
/**
* virConnectURIs:
* uris: pointer to a list to be filled with URI strings
*
* This functions returns the list of available connection
* URIs. The caller is responsible for freeing the returned
* strings, and the array they're stored in.
*
* Returns the number of URIs in case of success or -1 in
* case of error.
*/
int virConnectURIs(char ***uris);
This simply calls the existing probe() method for each driver and
stores the list of URIs returned.
Finally to tie this all together simply needs a little helper script
which by convention is added to the /etc/bash_completion.d/. On Fedora
this isn't enable by default, so you have to turn it on with
source /etc/bash_completion.d/virsh
To your $HOME/.bashrc
Daniel
[1] For a definition of 'everyone' which includes git & mercurial
b/src/virsh.bash | 79 +++++++
include/libvirt/libvirt.h | 1
include/libvirt/libvirt.h.in | 1
libvirt.spec.in | 1
src/Makefile.am | 10
src/libvirt.c | 54 +++++
src/libvirt_sym.version | 2
src/test.c | 6
src/virsh.c | 442 ++++++++++++++++++++++++++++++++++++++++++-
9 files changed, 581 insertions(+), 15 deletions(-)
diff -r f3413463b3ff include/libvirt/libvirt.h
--- a/include/libvirt/libvirt.h Sun Jul 13 13:14:50 2008 +0100
+++ b/include/libvirt/libvirt.h Mon Jul 14 11:54:10 2008 +0100
@@ -397,6 +397,7 @@
virConnectAuthPtr auth,
int flags);
int virConnectClose (virConnectPtr conn);
+int virConnectURIs (char ***uris);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
unsigned long *hvVer);
diff -r f3413463b3ff include/libvirt/libvirt.h.in
--- a/include/libvirt/libvirt.h.in Sun Jul 13 13:14:50 2008 +0100
+++ b/include/libvirt/libvirt.h.in Mon Jul 14 11:54:10 2008 +0100
@@ -397,6 +397,7 @@
virConnectAuthPtr auth,
int flags);
int virConnectClose (virConnectPtr conn);
+int virConnectURIs (char ***uris);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
unsigned long *hvVer);
diff -r f3413463b3ff libvirt.spec.in
--- a/libvirt.spec.in Sun Jul 13 13:14:50 2008 +0100
+++ b/libvirt.spec.in Mon Jul 14 11:54:10 2008 +0100
@@ -227,6 +227,7 @@
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/
%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/autostart
+%{_sysconfdir}/bash_completion.d/virsh
%{_sysconfdir}/rc.d/init.d/libvirtd
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
diff -r f3413463b3ff src/Makefile.am
--- a/src/Makefile.am Sun Jul 13 13:14:50 2008 +0100
+++ b/src/Makefile.am Mon Jul 14 11:54:10 2008 +0100
@@ -25,8 +25,9 @@
confdir = $(sysconfdir)/libvirt/
conf_DATA = qemu.conf
+bashdir = $(sysconfdir)/bash_completion.d
-EXTRA_DIST = libvirt_sym.version $(conf_DATA)
+EXTRA_DIST = libvirt_sym.version $(conf_DATA) virsh.bash
lib_LTLIBRARIES = libvirt.la
@@ -153,7 +154,12 @@
endif
# Create the /var/cache/libvirt directory when installing.
-install-exec-local:
+install-exec-local::
$(MKDIR_P) $(DESTDIR)$(localstatedir)/cache/libvirt
+ $(MKDIR_P) $(DESTDIR)$(bashdir)
+ $(INSTALL_SCRIPT) virsh.bash $(bashdir)/virsh
+
+uninstall-local::
+ $(RM) -f $(bashdir)/virsh
CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda
diff -r f3413463b3ff src/libvirt.c
--- a/src/libvirt.c Sun Jul 13 13:14:50 2008 +0100
+++ b/src/libvirt.c Mon Jul 14 11:54:10 2008 +0100
@@ -37,6 +37,7 @@
#include "uuid.h"
#include "util.h"
#include "test.h"
+#include "memory.h"
#include "xen_unified.h"
#include "remote_internal.h"
#include "qemu_driver.h"
@@ -701,7 +702,8 @@
int probes = 0;
for (i = 0; i < virDriverTabCount; i++) {
if ((virDriverTab[i]->probe != NULL) &&
- ((latest = virDriverTab[i]->probe()) != NULL)) {
+ ((latest = virDriverTab[i]->probe()) != NULL) &&
+ STRNEQ(latest, "test:///default")) {
probes++;
DEBUG("Probed %s", latest);
@@ -946,6 +948,56 @@
if (virUnrefConnect(conn) < 0)
return (-1);
return (0);
+}
+
+
+/**
+ * virConnectURIs:
+ * uris: pointer to a list to be filled with URI strings
+ *
+ * This functions returns the list of available connection
+ * URIs. The caller is responsible for freeing the returned
+ * strings, and the array they're stored in.
+ *
+ * Returns the number of URIs in case of success or -1 in
+ * case of error.
+ */
+int
+virConnectURIs(char ***uris)
+{
+ const char *uri;
+ char **ret = NULL;
+ int nuris = 0, i;
+ DEBUG("uris=%p", uris);
+
+ if (!initialized)
+ if (virInitialize() < 0)
+ return -1;
+
+ if (!uris)
+ return -1;
+
+ for (i = 0; i < virDriverTabCount; i++) {
+ if ((virDriverTab[i]->probe != NULL) &&
+ ((uri = virDriverTab[i]->probe()) != NULL)) {
+ if (VIR_REALLOC_N(ret, nuris + 1) < 0)
+ goto no_memory;
+ if ((ret[nuris++] = strdup(uri)) == NULL)
+ goto no_memory;
+
+ DEBUG("Probed %s", uri);
+ }
+ }
+
+ *uris = ret;
+ return (nuris);
+
+no_memory:
+ for (i = 0 ; i < nuris ; i++)
+ VIR_FREE(ret[i]);
+ VIR_FREE(ret);
+ virLibConnError(NULL, VIR_ERR_NO_MEMORY, NULL);
+ return -1;
}
/* Not for public use. This function is part of the internal
diff -r f3413463b3ff src/libvirt_sym.version
--- a/src/libvirt_sym.version Sun Jul 13 13:14:50 2008 +0100
+++ b/src/libvirt_sym.version Mon Jul 14 11:54:10 2008 +0100
@@ -5,7 +5,7 @@
virConnectOpenReadOnly;
virConnectOpenAuth;
virConnectAuthPtrDefault;
-
+ virConnectURIs;
virConnectClose;
virConnectGetType;
virConnectGetVersion;
diff -r f3413463b3ff src/test.c
--- a/src/test.c Sun Jul 13 13:14:50 2008 +0100
+++ b/src/test.c Mon Jul 14 11:54:10 2008 +0100
@@ -215,6 +215,10 @@
" </ip>"
"</network>";
+
+static const char *testProbe(void) {
+ return "test:///default";
+}
static int testOpenDefault(virConnectPtr conn) {
int u;
@@ -1545,7 +1549,7 @@
VIR_DRV_TEST,
"Test",
LIBVIR_VERSION_NUMBER,
- NULL, /* probe */
+ testProbe, /* probe */
testOpen, /* open */
testClose, /* close */
NULL, /* supports_feature */
diff -r f3413463b3ff src/virsh.bash
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/virsh.bash Mon Jul 14 11:54:10 2008 +0100
@@ -0,0 +1,79 @@
+
+_virsh()
+{
+ local cur prev cmd cmd_index arg arg_index i results
+ local virsh="$1"
+ local canonical=0
+
+ COMPREPLY=()
+ cur="$2"
+ prev="$3"
+
+ if [[ $COMP_CWORD > 1 && ${COMP_WORDS[COMP_CWORD-1]} = '--connect'
]]; then
+ results="$("$virsh" _complete-uri)" || nets=""
+ fi
+
+ if [ -z "$results" ]; then
+ # searching for the command name
+ for ((i=1; $i<=$COMP_CWORD; i++)); do
+ if [[ ${COMP_WORDS[i]} != -* ]]; then
+ if [[ ${COMP_WORDS[i-1]} != '--connect' ]]; then
+ if [[ $i < $COMP_CWORD ]]; then
+ cmd="${COMP_WORDS[i]}"
+ cmd_index=$i
+ arg_index=`expr $COMP_CWORD - $cmd_index`
+ break
+ fi
+ fi
+ fi
+ done
+
+ if [[ "$cur" == -* ]]; then
+ # Generate args - global or command specific
+ results="$("$virsh" _complete-command options
"$cmd")"
+ else
+ if [ -z "$cmd" ]; then
+ # No command set, so generate list of all commands
+ results="$("$virsh" _complete-command commands)" ||
commands=""
+ else
+ # Command set, to generate command specific args
+ n=0
+ for i in "$("$virsh" _complete-command arguments
"$cmd")"
+ do
+ n=`expr $n + 1`
+ if [ $n = $arg_index ]; then
+ arg=$i
+ break
+ fi
+ done
+
+ case $arg in
+ file)
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -o "default" --
"$cur"))
+ ;;
+
+ domain)
+ results="$("$virsh" _complete-domain)" ||
doms=""
+ ;;
+
+ network)
+ results="$("$virsh" _complete-network)" ||
nets=""
+ ;;
+
+ pool)
+ results="$("$virsh" _complete-pool)" ||
nets=""
+ ;;
+
+ uri)
+ results="$("$virsh" _complete-uri)" ||
nets=""
+ ;;
+ esac
+ fi
+ fi
+ fi
+ if [ ! -z "$results" ]; then
+ COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$results' --
"$cur"))
+ fi
+}
+
+complete -F _virsh virsh
diff -r f3413463b3ff src/virsh.c
--- a/src/virsh.c Sun Jul 13 13:14:50 2008 +0100
+++ b/src/virsh.c Mon Jul 14 11:54:10 2008 +0100
@@ -329,6 +329,409 @@
* ---------------
*/
+
+
+/*
+ * "_compcmds" command
+ */
+static vshCmdInfo info_compcommand[] = {
+ {"syntax", "_complete-command [commands|arguments|options]
[<command>]"},
+ {"help", gettext_noop("print shell completion data")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of
commands.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compcommand[] = {
+ {"type", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("type of
data")},
+ {"cmd", VSH_OT_DATA, 0, gettext_noop("command name")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompCommand(vshControl * ctl, vshCmd * cmd)
+{
+ const char *type = vshCommandOptString(cmd, "type", NULL);
+ const char *name = vshCommandOptString(cmd, "cmd", NULL);
+
+ if (STREQ(type, "commands")) {
+ vshCmdDef *def;
+ for (def = commands; def->name; def++)
+ if (def->name[0] != '_')
+ vshPrint(ctl, "%s\n", def->name);
+ } else if (STREQ(type, "options")) {
+ if (name) {
+ vshCmdDef *def = vshCmddefSearch(name);
+ if (!def) {
+ vshError(ctl, FALSE, _("command '%s' doesn't
exist"), name);
+ return FALSE;
+ } else if (def->opts) {
+ vshCmdOptDef *opt;
+ for (opt = def->opts; opt->name; opt++)
+ if (opt->type == VSH_OT_BOOL ||
+ opt->type == VSH_OT_INT ||
+ opt->type == VSH_OT_STRING)
+ vshPrint(ctl, "--%s\n", opt->name);
+ }
+ } else {
+ vshPrint(ctl,
+ "-c\n--connect\n"
+ "-r\n--readonly\n"
+ "-d\n--debug\n"
+ "-h\n--help\n"
+ "-q\n--quiet\n"
+ "-t\n--timing\n"
+ "-l\n--log\n"
+ "-v\n--version\n");
+ }
+ } else if (STREQ(type, "arguments")) {
+ if (!name) {
+ vshError(ctl, FALSE, "%s", _("no command specified"));
+ return FALSE;
+ } else {
+ vshCmdDef *def = vshCmddefSearch(name);
+ if (!def) {
+ vshError(ctl, FALSE, _("command '%s' doesn't
exist"), name);
+ return FALSE;
+ } else if (def->opts) {
+ vshCmdOptDef *opt;
+ for (opt = def->opts; opt->name; opt++)
+ if (opt->type == VSH_OT_DATA)
+ vshPrint(ctl, "%s\n", opt->name);
+ }
+ }
+ }
+ return TRUE;
+}
+
+/*
+ * "_compuris" command
+ */
+static vshCmdInfo info_compuri[] = {
+ {"syntax", "_complete-uri"},
+ {"help", gettext_noop("print shell completion data for URIs")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of
URIs.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compuri[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompUri(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **uris = NULL;
+ int nuris, i;
+
+ nuris = virConnectURIs(&uris);
+ if (nuris < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list connection
URIs"));
+ return FALSE;
+ }
+ for (i = 0 ; i < nuris ; i++) {
+ vshPrint(ctl, "%s\n", uris[i]);
+ free(uris[i]);
+ }
+
+ free(uris);
+ return TRUE;
+}
+/*
+ * "_compdomains" command
+ */
+static vshCmdInfo info_compdomain[] = {
+ {"syntax", "_complete-domain"},
+ {"help", gettext_noop("print shell completion data for
domains")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of
domains.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compdomain[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompDomain(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ int *ids = NULL;
+ char **names = NULL;
+ int maxname = 0, maxid = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ maxid = virConnectNumOfDomains(ctl->conn);
+ if (maxid < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active
domains"));
+ return FALSE;
+ }
+ if (maxid) {
+ ids = vshMalloc(ctl, sizeof(int) * maxid);
+
+ if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active
domains"));
+ free(ids);
+ return FALSE;
+ }
+
+ qsort(&ids[0], maxid, sizeof(int), idsorter);
+ }
+ maxname = virConnectNumOfDefinedDomains(ctl->conn);
+ if (maxname < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive
domains"));
+ free(ids);
+ return FALSE;
+ }
+ if (maxname) {
+ names = vshMalloc(ctl, sizeof(char *) * maxname);
+
+ if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) <
0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive
domains"));
+ free(ids);
+ free(names);
+ return FALSE;
+ }
+
+ qsort(&names[0], maxname, sizeof(char*), namesorter);
+ }
+
+ for (i = 0; i < maxid; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]);
+ /* this kind of work with domains is not atomic operation */
+ if (!dom)
+ continue;
+ virDomainGetUUIDString(dom, uuid);
+ vshPrint(ctl, "%d\n%s\n%s\n",
+ virDomainGetID(dom),
+ virDomainGetName(dom),
+ uuid);
+ virDomainFree(dom);
+ }
+ for (i = 0; i < maxname; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]);
+
+ /* this kind of work with domains is not atomic operation */
+ if (!dom) {
+ free(names[i]);
+ continue;
+ }
+ virDomainGetUUIDString(dom, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virDomainGetName(dom),
+ uuid);
+ virDomainFree(dom);
+ free(names[i]);
+ }
+ free(ids);
+ free(names);
+ return TRUE;
+}
+
+/*
+ * "_compnetworks" command
+ */
+static vshCmdInfo info_compnetwork[] = {
+ {"syntax", "_complete-network"},
+ {"help", gettext_noop("print shell completion data for
networks")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of
networks.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_compnetwork[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompNetwork(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **activeNames = NULL, **inactiveNames = NULL;
+ int maxactive = 0, maxinactive = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ maxactive = virConnectNumOfNetworks(ctl->conn);
+ if (maxactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active
networks"));
+ return FALSE;
+ }
+ if (maxactive) {
+ activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
+
+ if ((maxactive = virConnectListNetworks(ctl->conn, activeNames,
+ maxactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active
networks"));
+ free(activeNames);
+ return FALSE;
+ }
+
+ qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
+ }
+ maxinactive = virConnectNumOfDefinedNetworks(ctl->conn);
+ if (maxinactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive
networks"));
+ free(activeNames);
+ return FALSE;
+ }
+ if (maxinactive) {
+ inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
+
+ if ((maxinactive = virConnectListDefinedNetworks(ctl->conn, inactiveNames,
maxinactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive
networks"));
+ free(activeNames);
+ free(inactiveNames);
+ return FALSE;
+ }
+
+ qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
+ }
+
+ for (i = 0; i < maxactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virNetworkPtr network = virNetworkLookupByName(ctl->conn, activeNames[i]);
+
+ /* this kind of work with networks is not atomic operation */
+ if (!network) {
+ free(activeNames[i]);
+ continue;
+ }
+ virNetworkGetUUIDString(network, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virNetworkGetName(network),
+ uuid);
+ virNetworkFree(network);
+ free(activeNames[i]);
+ }
+ for (i = 0; i < maxinactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virNetworkPtr network = virNetworkLookupByName(ctl->conn, inactiveNames[i]);
+
+ /* this kind of work with networks is not atomic operation */
+ if (!network) {
+ free(inactiveNames[i]);
+ continue;
+ }
+ virNetworkGetUUIDString(network, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virNetworkGetName(network),
+ uuid);
+
+ virNetworkFree(network);
+ free(inactiveNames[i]);
+ }
+ free(activeNames);
+ free(inactiveNames);
+
+ return TRUE;
+}
+
+
+/*
+ * "_comppools" command
+ */
+static vshCmdInfo info_comppool[] = {
+ {"syntax", "_complete-pool"},
+ {"help", gettext_noop("print shell completion data for pools")},
+ {"desc", gettext_noop("Prints data useful for shell autocompletion of
pools.")},
+
+ {NULL, NULL}
+};
+
+static vshCmdOptDef opts_comppool[] = {
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdCompPool(vshControl * ctl, vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **activeNames = NULL, **inactiveNames = NULL;
+ int maxactive = 0, maxinactive = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ maxactive = virConnectNumOfStoragePools(ctl->conn);
+ if (maxactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active
pools"));
+ return FALSE;
+ }
+ if (maxactive) {
+ activeNames = vshMalloc(ctl, sizeof(char *) * maxactive);
+
+ if ((maxactive = virConnectListStoragePools(ctl->conn, activeNames,
+ maxactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list active
pools"));
+ free(activeNames);
+ return FALSE;
+ }
+
+ qsort(&activeNames[0], maxactive, sizeof(char *), namesorter);
+ }
+ maxinactive = virConnectNumOfDefinedStoragePools(ctl->conn);
+ if (maxinactive < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive
pools"));
+ free(activeNames);
+ return FALSE;
+ }
+ if (maxinactive) {
+ inactiveNames = vshMalloc(ctl, sizeof(char *) * maxinactive);
+
+ if ((maxinactive = virConnectListDefinedStoragePools(ctl->conn, inactiveNames,
maxinactive)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list inactive
pools"));
+ free(activeNames);
+ free(inactiveNames);
+ return FALSE;
+ }
+
+ qsort(&inactiveNames[0], maxinactive, sizeof(char*), namesorter);
+ }
+
+ for (i = 0; i < maxactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn,
activeNames[i]);
+
+ /* this kind of work with pools is not atomic operation */
+ if (!pool) {
+ free(activeNames[i]);
+ continue;
+ }
+ virStoragePoolGetUUIDString(pool, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virStoragePoolGetName(pool),
+ uuid);
+ virStoragePoolFree(pool);
+ free(activeNames[i]);
+ }
+ for (i = 0; i < maxinactive; i++) {
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ virStoragePoolPtr pool = virStoragePoolLookupByName(ctl->conn,
inactiveNames[i]);
+
+ /* this kind of work with pools is not atomic operation */
+ if (!pool) {
+ free(inactiveNames[i]);
+ continue;
+ }
+ virStoragePoolGetUUIDString(pool, uuid);
+ vshPrint(ctl, "%s\n%s\n",
+ virStoragePoolGetName(pool),
+ uuid);
+
+ virStoragePoolFree(pool);
+ free(inactiveNames[i]);
+ }
+ free(activeNames);
+ free(inactiveNames);
+
+ return TRUE;
+}
+
+
/*
* "help" command
*/
@@ -355,8 +758,9 @@
vshPrint(ctl, "%s", _("Commands:\n\n"));
for (def = commands; def->name; def++)
- vshPrint(ctl, " %-15s %s\n", def->name,
- N_(vshCmddefGetInfo(def, "help")));
+ if (def->name[0] != '_')
+ vshPrint(ctl, " %-15s %s\n", def->name,
+ N_(vshCmddefGetInfo(def, "help")));
return TRUE;
}
return vshCmddefHelp(ctl, cmdname, FALSE);
@@ -426,7 +830,7 @@
};
static vshCmdOptDef opts_connect[] = {
- {"name", VSH_OT_DATA, 0, gettext_noop("hypervisor connection
URI")},
+ {"uri", VSH_OT_DATA, 0, gettext_noop("hypervisor connection
URI")},
{"readonly", VSH_OT_BOOL, 0, gettext_noop("read-only
connection")},
{NULL, 0, 0, NULL}
};
@@ -446,7 +850,7 @@
}
free(ctl->name);
- ctl->name = vshStrdup(ctl, vshCommandOptString(cmd, "name", NULL));
+ ctl->name = vshStrdup(ctl, vshCommandOptString(cmd, "uri", NULL));
if (!ro) {
ctl->conn = virConnectOpen(ctl->name);
@@ -1004,7 +1408,7 @@
};
static vshCmdOptDef opts_start[] = {
- {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the
inactive domain")},
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the
inactive domain")},
{NULL, 0, 0, NULL}
};
@@ -1017,7 +1421,7 @@
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
- if (!(dom = vshCommandOptDomainBy(ctl, cmd, "name", NULL, VSH_BYNAME)))
+ if (!(dom = vshCommandOptDomainBy(ctl, cmd, "domain", NULL, VSH_BYNAME)))
return FALSE;
if (virDomainGetID(dom) != (unsigned int)-1) {
@@ -2650,7 +3054,7 @@
};
static vshCmdOptDef opts_network_start[] = {
- {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the
inactive network")},
+ {"network", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the
inactive network")},
{NULL, 0, 0, NULL}
};
@@ -2663,7 +3067,7 @@
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
- if (!(network = vshCommandOptNetworkBy(ctl, cmd, "name", NULL,
VSH_BYNAME)))
+ if (!(network = vshCommandOptNetworkBy(ctl, cmd, "network", NULL,
VSH_BYNAME)))
return FALSE;
if (virNetworkCreate(network) == 0) {
@@ -3554,7 +3958,7 @@
};
static vshCmdOptDef opts_pool_start[] = {
- {"name", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the
inactive pool")},
+ {"pool", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("name of the
inactive pool")},
{NULL, 0, 0, NULL}
};
@@ -3567,7 +3971,7 @@
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
return FALSE;
- if (!(pool = vshCommandOptPoolBy(ctl, cmd, "name", NULL, VSH_BYNAME)))
+ if (!(pool = vshCommandOptPoolBy(ctl, cmd, "pool", NULL, VSH_BYNAME)))
return FALSE;
if (virStoragePoolCreate(pool, 0) == 0) {
@@ -5074,6 +5478,12 @@
* Commands
*/
static vshCmdDef commands[] = {
+ {"_complete-command", cmdCompCommand, opts_compcommand, info_compcommand},
+ {"_complete-uri", cmdCompUri, opts_compuri, info_compuri},
+ {"_complete-domain", cmdCompDomain, opts_compdomain, info_compdomain},
+ {"_complete-network", cmdCompNetwork, opts_compnetwork, info_compnetwork},
+ {"_complete-pool", cmdCompPool, opts_comppool, info_comppool},
+
{"help", cmdHelp, opts_help, info_help},
{"attach-device", cmdAttachDevice, opts_attach_device,
info_attach_device},
{"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk},
@@ -6514,6 +6924,18 @@
ret = vshCommandParse(ctl, cmdstr);
free(cmdstr);
+
+ /* Special case 'help' to avoid virConnectOpen */
+ if (ctl->cmd &&
+ ctl->cmd->def &&
+ ctl->cmd->def->name &&
+ (STREQ(ctl->cmd->def->name, "help") ||
+ STREQ(ctl->cmd->def->name, "_complete-command") ||
+ STREQ(ctl->cmd->def->name, "_complete-uri"))) {
+ ret = vshCommandRun(ctl, ctl->cmd);
+ exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+
return ret;
}
return TRUE;
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|