Quoting Daniel P. Berrange (berrange(a)redhat.com):
On Thu, Oct 06, 2011 at 08:30:55AM -0500, Serge E. Hallyn wrote:
> Quoting Daniel P. Berrange (berrange(a)redhat.com):
> > On Wed, Oct 05, 2011 at 03:17:47PM -0500, Serge E. Hallyn wrote:
> > > Hi,
> > >
> > > I've been trying out a bash autocompletion file by Geoff Low (slight
hack
> > > by me, don't blame him for my hack), and it's working pretty
nicely.
> > > I'm not sure where to put it in the git tree, but it seems like
it'd be
> > > nice to have upstream?
> >
> > David Lutterkort previously suggested this
> >
> >
https://www.redhat.com/archives/libvir-list/2007-October/msg00231.html
> >
> > And I didn't ever notice that and so wrote one myself
> >
> >
https://www.redhat.com/archives/libvir-list/2008-July/msg00175.html
> >
https://www.redhat.com/archives/libvir-list/2008-July/msg00177.html
> >
> > Neither ever got committed. There were some things I didn't much like
> > about mine, but I can't really remember now.
> >
> > Third time lucky perhaps :-)
>
> So the things you didn't much like must not have been *too* bad? :)
> Are you going to make some changes and resubmit, or would you like
> me to test (and port as needed) the above patches first?
I don't have time right now to update my own patches. You, or anyone
else, are free to take them forward as desired...
Well I've got the patch ported so that it mostly works - autocompletes
for commands and vm names at least. (ugly patch against 0.9.8 attached
just for conversation) But I can't figure out how one should do uri
completion. Any hints on where to get such a list now?
thanks,
-serge
Index: libvirt-0.9.8/include/libvirt/libvirt.h
===================================================================
--- libvirt-0.9.8.orig/include/libvirt/libvirt.h 2011-12-08 06:58:49.000000000 +0000
+++ libvirt-0.9.8/include/libvirt/libvirt.h 2012-02-08 03:52:16.008232120 +0000
@@ -1065,6 +1065,7 @@
unsigned int flags);
int virConnectRef (virConnectPtr conn);
int virConnectClose (virConnectPtr conn);
+char ** virConnectURIs (int *nuris);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
unsigned long *hvVer);
Index: libvirt-0.9.8/include/libvirt/libvirt.h.in
===================================================================
--- libvirt-0.9.8.orig/include/libvirt/libvirt.h.in 2011-12-06 08:38:51.000000000 +0000
+++ libvirt-0.9.8/include/libvirt/libvirt.h.in 2012-02-08 03:52:35.132225305 +0000
@@ -1065,6 +1065,7 @@
unsigned int flags);
int virConnectRef (virConnectPtr conn);
int virConnectClose (virConnectPtr conn);
+char ** virConnectURIs (int *nuris);
const char * virConnectGetType (virConnectPtr conn);
int virConnectGetVersion (virConnectPtr conn,
unsigned long *hvVer);
Index: libvirt-0.9.8/libvirt.spec.in
===================================================================
--- libvirt-0.9.8.orig/libvirt.spec.in 2011-12-08 06:54:48.000000000 +0000
+++ libvirt-0.9.8/libvirt.spec.in 2012-02-08 03:54:03.300230906 +0000
@@ -1050,6 +1050,7 @@
%{_unitdir}/libvirtd.service
%endif
%doc daemon/libvirtd.upstart
+%{_sysconfdir}/bash_completion.d/virsh
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
%if 0%{?fedora} >= 14 || 0%{?rhel} >= 6
Index: libvirt-0.9.8/src/Makefile.am
===================================================================
--- libvirt-0.9.8.orig/src/Makefile.am 2012-02-08 03:46:38.000000000 +0000
+++ libvirt-0.9.8/src/Makefile.am 2012-02-08 20:51:04.340232096 +0000
@@ -22,7 +22,9 @@
$(COVERAGE_CFLAGS)
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
-EXTRA_DIST = $(conf_DATA) util/keymaps.csv
+bashdir = $(sysconfdir)/bash_completion.d
+
+EXTRA_DIST = $(conf_DATA) util/keymaps.csv virsh.bash
BUILT_SOURCES =
CLEANFILES =
@@ -1584,6 +1586,8 @@
$(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml && \
rm $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml.t; }
endif
+ $(MKDIR_P) "$(DESTDIR)$(bashdir)"
+ $(INSTALL_DATA) "$(srcdir)/virsh.bash" "$(DESTDIR)$(bashdir)/virsh"
uninstall-local::
rmdir "$(DESTDIR)$(localstatedir)/cache/libvirt" ||:
@@ -1621,6 +1625,7 @@
rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/network" ||:
endif
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt" ||:
+ rm -f "$(DESTDIR)$(bashdir)/virsh" ||:
CLEANFILES += *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda *.i *.s
DISTCLEANFILES += $(GENERATED_SYM_FILES)
Index: libvirt-0.9.8/src/libvirt.c
===================================================================
--- libvirt-0.9.8.orig/src/libvirt.c 2011-12-08 02:26:59.000000000 +0000
+++ libvirt-0.9.8/src/libvirt.c 2012-02-09 04:13:30.168233577 +0000
@@ -1317,6 +1317,77 @@
}
/**
+ * virConnectURIs:
+ * @nuris: pointer to an integer in which to store the number of URIS
+ *
+ * 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 URIs in case of success or NULL case of error.
+ */
+char **
+virConnectURIs(int *nuris)
+{
+ char **ret = NULL;
+ int i;
+ int n = 0;
+
+ if (!initialized)
+ if (virInitialize() < 0)
+ return NULL;
+
+ for (i = 0; i < virDriverTabCount; i++) {
+ virConnectPtr conn;
+ int res;
+
+ printf("URI %d: 1, name %s\n", i, virDriverTab[i]->name);
+ conn = virGetConnect();
+ if (!conn)
+ goto no_memory;
+ printf("URI %d: 2\n", i);
+ res = virDriverTab[i]->open (conn, NULL, 0);
+ printf("URI %d: 3\n", i);
+ if (res != VIR_DRV_OPEN_SUCCESS)
+ goto next;
+ printf("URI %d: 4\n", i);
+ if (!conn->uri)
+ goto next;
+ printf("URI %d: 5\n", i);
+ if (VIR_REALLOC_N(ret, n+1) < 0) {
+ printf("URI %d: 6\n", i);
+ virConnectClose(conn);
+ goto no_memory;
+ }
+ printf("URI %d: 7, conn->uri is\n", i, conn->uri);
+ if ((ret[n++] = strdup(conn->uri)) == NULL) {
+ printf("URI %d: 8\n", i);
+ virConnectClose(conn);
+ goto no_memory;
+ }
+ printf("URI %d: 9\n", i);
+next:
+ printf("URI %d: 10\n", i);
+ virConnectClose(conn);
+ }
+
+ *nuris = n;
+ printf("URI %d: 11\n", *nuris);
+ for (i=0; i<n; i++)
+ printf("uri %d: %s\n", i, ret[i]);
+ return ret;
+
+no_memory:
+ printf("URI %d: 12\n", *nuris);
+ for (i = 0 ; i < n ; i++)
+ VIR_FREE(ret[i]);
+ VIR_FREE(ret);
+ *nuris = 0;
+ virLibConnError(VIR_ERR_NO_MEMORY, __FUNCTION__);
+ return NULL;
+}
+
+/**
* virConnectOpen:
* @name: URI of the hypervisor
*
Index: libvirt-0.9.8/src/libvirt_public.syms
===================================================================
--- libvirt-0.9.8.orig/src/libvirt_public.syms 2011-12-02 03:59:50.000000000 +0000
+++ libvirt-0.9.8/src/libvirt_public.syms 2012-02-08 04:03:52.360265205 +0000
@@ -506,6 +506,7 @@
virDomainGetBlockIoTune;
virDomainSetBlockIoTune;
virNodeSuspendForDuration;
+ virConnectURIs;
} LIBVIRT_0.9.7;
# .... define new API here using predicted next version number ....
Index: libvirt-0.9.8/src/virsh.bash
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ libvirt-0.9.8/src/virsh.bash 2012-02-08 22:56:26.536232538 +0000
@@ -0,0 +1,83 @@
+_virsh()
+{
+ local cur prev cmd cmd_index arg arg_index i results skipconn
+ 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
+
+ skipconn=0
+ 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
+ echo "${COMP_WORDS[i]}" | grep '///' >/dev/null
2>&1
+ test "$?" = 1 && skipconn=1
+ test "$skipconn" = 0 && virsh="$virsh
${COMP_WORDS[i-1]} ${COMP_WORDS[i]}"
+ else
+ 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)
+ test "$skipconn" = 0 && results="$($virsh
_complete-domain)" || doms=""
+ ;;
+
+ network)
+ test "$skipconn" = 0 && results="$($virsh
_complete-network)" || nets=""
+ ;;
+
+ pool)
+ test "$skipconn" = 0 && 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
Index: libvirt-0.9.8/tools/virsh.c
===================================================================
--- libvirt-0.9.8.orig/tools/virsh.c 2012-02-08 03:46:38.000000000 +0000
+++ libvirt-0.9.8/tools/virsh.c 2012-02-08 22:31:14.928233016 +0000
@@ -623,6 +623,414 @@
*/
/*
+ * "_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 bool
+cmdCompCommand(vshControl * ctl, const vshCmd * cmd)
+{
+ const char *type;
+ const char *name;
+
+ if (vshCommandOptString(cmd, "type", &type) <= 0)
+ type = "commands";
+ if (vshCommandOptString(cmd, "cmd", &name) <= 0)
+ name = NULL;
+
+ if (STREQ(type, "commands")) {
+ const vshCmdGrp *grp;
+ const vshCmdDef *def;
+ for (grp = cmdGroups; grp->name; grp++) {
+ for (def = grp->commands; def->name; def++)
+ if (def->name[0] != '_')
+ vshPrint(ctl, "%s\n", def->name);
+ }
+ } else if (STREQ(type, "options")) {
+ if (name) {
+ const vshCmdDef *def = vshCmddefSearch(name);
+ if (!def) {
+ vshError(ctl, _("command '%s' doesn't exist"),
name);
+ return false;
+ } else if (def->opts) {
+ const 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, "%s", _("no command specified"));
+ return false;
+ } else {
+ const vshCmdDef *def = vshCmddefSearch(name);
+ if (!def) {
+ vshError(ctl, _("command '%s' doesn't exist"),
name);
+ return false;
+ } else if (def->opts) {
+ const 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 bool
+cmdCompUri(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **uris = NULL;
+ int nuris, i;
+
+ uris = virConnectURIs(&nuris);
+ if (!uris) {
+ vshError(ctl, "%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 bool
+cmdCompDomain(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ int *ids = NULL;
+ char **names = NULL;
+ int maxname = 0, maxid = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ return false;
+
+ maxid = virConnectNumOfDomains(ctl->conn);
+ if (maxid < 0) {
+ vshError(ctl, "%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, "%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, "%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, "%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 bool
+cmdCompNetwork(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **activeNames = NULL, **inactiveNames = NULL;
+ int maxactive = 0, maxinactive = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ return false;
+
+ maxactive = virConnectNumOfNetworks(ctl->conn);
+ if (maxactive < 0) {
+ vshError(ctl, "%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, "%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, "%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, "%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 bool
+cmdCompPool(vshControl * ctl, const vshCmd * cmd ATTRIBUTE_UNUSED)
+{
+ char **activeNames = NULL, **inactiveNames = NULL;
+ int maxactive = 0, maxinactive = 0, i;
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ return false;
+
+ maxactive = virConnectNumOfStoragePools(ctl->conn);
+ if (maxactive < 0) {
+ vshError(ctl, "%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, "%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, "%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, "%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
*/
static const vshCmdInfo info_help[] = {
@@ -654,7 +1062,8 @@
grp->keyword);
for (def = grp->commands; def->name; def++)
- vshPrint(ctl, " %-30s %s\n", def->name,
+ if (def->name[0] != '_')
+ vshPrint(ctl, " %-30s %s\n", def->name,
_(vshCmddefGetInfo(def, "help")));
vshPrint(ctl, "\n");
@@ -15335,6 +15744,11 @@
};
static const vshCmdDef virshCmds[] = {
+ {"_complete-command", cmdCompCommand, opts_compcommand, info_compcommand,
VSH_CMD_FLAG_NOCONNECT},
+ {"_complete-uri", cmdCompUri, opts_compuri, info_compuri,
VSH_CMD_FLAG_NOCONNECT},
+ {"_complete-domain", cmdCompDomain, opts_compdomain, info_compdomain,
VSH_CMD_FLAG_NOCONNECT},
+ {"_complete-network", cmdCompNetwork, opts_compnetwork, info_compnetwork,
VSH_CMD_FLAG_NOCONNECT},
+ {"_complete-pool", cmdCompPool, opts_comppool, info_comppool,
VSH_CMD_FLAG_NOCONNECT},
{"cd", cmdCd, opts_cd, info_cd, VSH_CMD_FLAG_NOCONNECT},
{"echo", cmdEcho, opts_echo, info_echo, VSH_CMD_FLAG_NOCONNECT},
{"exit", cmdQuit, NULL, info_quit, VSH_CMD_FLAG_NOCONNECT},
@@ -16606,6 +17020,7 @@
vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
{
vshCommandParser parser;
+ bool ret;
if (nargs <= 0)
return false;
@@ -16613,7 +17028,20 @@
parser.arg_pos = argv;
parser.arg_end = argv + nargs;
parser.getNextArg = vshCommandArgvGetArg;
- return vshCommandParse(ctl, &parser);
+ ret = vshCommandParse(ctl, &parser);
+
+ /* 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;
}
/* ----------------------
Index: libvirt-0.9.8/python/generator.py
===================================================================
--- libvirt-0.9.8.orig/python/generator.py 2011-12-02 03:59:49.000000000 +0000
+++ libvirt-0.9.8/python/generator.py 2012-02-08 20:01:59.268229464 +0000
@@ -224,6 +224,7 @@
qemu_functions_failed = []
functions_skipped = [
"virConnectListDomains",
+ "virConnectURIs",
]
qemu_functions_skipped = []
@@ -340,6 +341,7 @@
'virConnectGetVersion',
'virConnectGetLibVersion',
'virConnectListDomainsID',
+ 'virConnectURIs',
'virConnectListDefinedDomains',
'virConnectListNetworks',
'virConnectListDefinedNetworks',
@@ -428,6 +430,7 @@
# functions than those already listed
skip_function = (
'virConnectListDomains', # Python API is called virConectListDomainsID for
unknown reasons
+ 'virConnectURIs',
'virConnSetErrorFunc', # Not used in Python API XXX is this a bug ?
'virResetError', # Not used in Python API XXX is this a bug ?
'virGetVersion', # Python C code is manually written
Index: libvirt-0.9.8/src/Makefile.in
===================================================================
--- libvirt-0.9.8.orig/src/Makefile.in 2012-02-08 03:46:38.000000000 +0000
+++ libvirt-0.9.8/src/Makefile.in 2012-02-08 20:51:29.580231787 +0000
@@ -2548,6 +2548,8 @@
AM_LDFLAGS = $(COVERAGE_LDFLAGS)
+bashdir = $(sysconfdir)/bash_completion.d
+
# Add all conditional sources just in case...
EXTRA_DIST = $(conf_DATA) util/keymaps.csv $(srcdir)/util/virkeymaps.h \
$(srcdir)/util/keymaps.csv $(srcdir)/util/virkeycode-mapgen.py \
@@ -2586,7 +2588,7 @@
rpc/gensystemtap.pl rpc/virnetprotocol.x \
rpc/virkeepaliveprotocol.x $(am__append_137) $(am__append_139) \
$(STORAGE_HELPER_DISK_SOURCES) $(LXC_CONTROLLER_SOURCES) \
- $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES)
+ $(SECURITY_DRIVER_APPARMOR_HELPER_SOURCES) virsh.bash
BUILT_SOURCES = $(ESX_DRIVER_GENERATED) $(HYPERV_DRIVER_GENERATED) \
$(GENERATED_SYM_FILES) $(am__append_128) $(am__append_133) \
$(VIR_NET_RPC_GENERATED)
@@ -7016,6 +7018,8 @@
@WITH_NETWORK_TRUE@ cp $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml.t \
@WITH_NETWORK_TRUE@ $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml
&& \
@WITH_NETWORK_TRUE@ rm $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml.t;
}
+ $(MKDIR_P) "$(DESTDIR)$(bashdir)"
+ $(INSTALL_DATA) "$(srcdir)/virsh.bash" "$(DESTDIR)$(bashdir)/virsh"
uninstall-local::
rmdir "$(DESTDIR)$(localstatedir)/cache/libvirt" ||:
@@ -7041,6 +7045,7 @@
@WITH_NETWORK_TRUE@ rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt/network" ||:
@WITH_NETWORK_TRUE@ rmdir "$(DESTDIR)$(localstatedir)/run/libvirt/network" ||:
rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt" ||:
+ rm -f "$(DESTDIR)$(bashdir)/virsh" ||:
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.