Complete with the indexed targets (e.g. vda[3]) based on existing indexes. Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- tools/virsh-completer-domain.c | 100 +++++++++++++++++++++++++++++++++ tools/virsh-completer-domain.h | 5 ++ tools/virsh-domain.c | 3 + 3 files changed, 108 insertions(+) diff --git a/tools/virsh-completer-domain.c b/tools/virsh-completer-domain.c index 34985f6281..93e992e9b1 100644 --- a/tools/virsh-completer-domain.c +++ b/tools/virsh-completer-domain.c @@ -32,6 +32,7 @@ #include "virperf.h" #include "virbitmap.h" #include "virkeycode.h" +#include "virglibutil.h" #include "virkeynametable_linux.h" #include "virkeynametable_osx.h" #include "virkeynametable_win32.h" @@ -256,6 +257,105 @@ virshDomainUndefineStorageDisksCompleter(vshControl *ctl, } +static GSList * +virshDomainBlockjobBaseTopCompleteDisk(const char *target, + xmlXPathContext *ctxt) +{ + g_autofree xmlNodePtr *indexlist = NULL; + int nindexlist = 0; + size_t i; + GSList *ret = NULL; + + if ((nindexlist = virXPathNodeSet("./source|./backingStore", + ctxt, &indexlist)) < 0) + return NULL; + + ret = g_slist_prepend(ret, g_strdup(target)); + + for (i = 0; i < nindexlist; i++) { + g_autofree char *idx = virXMLPropString(indexlist[i], "index"); + + if (!idx) + continue; + + ret = g_slist_prepend(ret, g_strdup_printf("%s[%s]", target, idx)); + } + + return ret; +} + + +char ** +virshDomainBlockjobBaseTopCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags) +{ + virshControl *priv = ctl->privData; + g_autoptr(xmlDoc) xmldoc = NULL; + g_autoptr(xmlXPathContext) ctxt = NULL; + g_autofree xmlNodePtr *disks = NULL; + int ndisks; + size_t i; + const char *path = NULL; + g_autoptr(virGSListString) list = NULL; + GSList *n; + GStrv ret = NULL; + size_t nelems; + + virCheckFlags(0, NULL); + + if (!priv->conn || virConnectIsAlive(priv->conn) <= 0) + return NULL; + + if (virshDomainGetXML(ctl, cmd, 0, &xmldoc, &ctxt) < 0) + return NULL; + + ignore_value(vshCommandOptStringQuiet(ctl, cmd, "path", &path)); + + if ((ndisks = virXPathNodeSet("./devices/disk", ctxt, &disks)) <= 0) + return NULL; + + for (i = 0; i < ndisks; i++) { + g_autofree char *disktarget = NULL; + + ctxt->node = disks[i]; + disktarget = virXPathString("string(./target/@dev)", ctxt); + + if (STREQ_NULLABLE(path, disktarget)) + break; + } + + if (i == ndisks) + path = NULL; + + for (i = 0; i < ndisks; i++) { + g_autofree char *disktarget = NULL; + GSList *tmplist; + + ctxt->node = disks[i]; + + if (!(disktarget = virXPathString("string(./target/@dev)", ctxt))) + return NULL; + + if (path && STRNEQ(path, disktarget)) + continue; + + /* note that ctxt->node moved */ + if ((tmplist = virshDomainBlockjobBaseTopCompleteDisk(disktarget, ctxt))) + list = g_slist_concat(tmplist, list); + } + + list = g_slist_reverse(list); + nelems = g_slist_length(list); + ret = g_new0(char *, nelems + 1); + i = 0; + + for (n = list; n; n = n->next) + ret[i++] = g_strdup(n->data); + + return ret; +} + char ** virshDomainEventNameCompleter(vshControl *ctl G_GNUC_UNUSED, const vshCmd *cmd G_GNUC_UNUSED, diff --git a/tools/virsh-completer-domain.h b/tools/virsh-completer-domain.h index 1ed3f94094..ec7909888e 100644 --- a/tools/virsh-completer-domain.h +++ b/tools/virsh-completer-domain.h @@ -176,3 +176,8 @@ char ** virshDomainUndefineStorageDisksCompleter(vshControl *ctl, const vshCmd *cmd, unsigned int completeflags); + +char ** +virshDomainBlockjobBaseTopCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags); diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c index d2e604f5dd..1d8af2d274 100644 --- a/tools/virsh-domain.c +++ b/tools/virsh-domain.c @@ -1991,6 +1991,7 @@ static const vshCmdOptDef opts_blockcommit[] = { }, {.name = "base", .type = VSH_OT_STRING, + .completer = virshDomainBlockjobBaseTopCompleter, .help = N_("path of base file to commit into (default bottom of chain)") }, {.name = "shallow", @@ -1999,6 +2000,7 @@ static const vshCmdOptDef opts_blockcommit[] = { }, {.name = "top", .type = VSH_OT_STRING, + .completer = virshDomainBlockjobBaseTopCompleter, .help = N_("path of top file to commit from (default top of chain)") }, {.name = "active", @@ -2772,6 +2774,7 @@ static const vshCmdOptDef opts_blockpull[] = { }, {.name = "base", .type = VSH_OT_STRING, + .completer = virshDomainBlockjobBaseTopCompleter, .help = N_("path of backing file in chain for a partial pull") }, {.name = "wait", -- 2.31.1