snapshot: virsh fallback for snapshot-list --from children

Iterating over one level of children requires parsing all snapshots
and their parents; a bit of code shuffling makes it pretty easy
to do this as well.

* tools/virsh.c (cmdSnapshotList): Add another fallback.
This commit is contained in:
Eric Blake 2011-09-29 15:57:52 -06:00
parent 510823018e
commit 16d7b3908e

View File

@ -13161,6 +13161,7 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
information needed, 1 for parent column */ information needed, 1 for parent column */
int numsnaps; int numsnaps;
char **names = NULL; char **names = NULL;
char **parents = NULL;
int actual = 0; int actual = 0;
int i; int i;
xmlDocPtr xml = NULL; xmlDocPtr xml = NULL;
@ -13176,6 +13177,7 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
bool tree = vshCommandOptBool(cmd, "tree"); bool tree = vshCommandOptBool(cmd, "tree");
const char *from = NULL; const char *from = NULL;
virDomainSnapshotPtr start = NULL; virDomainSnapshotPtr start = NULL;
bool descendants = false;
if (vshCommandOptString(cmd, "from", &from) < 0) { if (vshCommandOptString(cmd, "from", &from) < 0) {
vshError(ctl, _("invalid from argument '%s'"), from); vshError(ctl, _("invalid from argument '%s'"), from);
@ -13219,27 +13221,29 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
goto cleanup; goto cleanup;
if (from) { if (from) {
descendants = vshCommandOptBool(cmd, "descendants");
start = virDomainSnapshotLookupByName(dom, from, 0); start = virDomainSnapshotLookupByName(dom, from, 0);
if (!start) if (!start)
goto cleanup; goto cleanup;
if (vshCommandOptBool(cmd, "descendants") || tree) { if (descendants || tree) {
flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; flags |= VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS;
} }
numsnaps = ctl->useSnapshotOld ? -1 : numsnaps = ctl->useSnapshotOld ? -1 :
virDomainSnapshotNumChildren(start, flags); virDomainSnapshotNumChildren(start, flags);
/* XXX Is it worth emulating --from without --tree on older servers? */ if (numsnaps < 0) {
if (tree) { /* XXX also want to emulate --descendants without --tree */
if (numsnaps >= 0) { if ((!descendants || tree) &&
numsnaps++; (ctl->useSnapshotOld ||
} else if (ctl->useSnapshotOld || last_error->code == VIR_ERR_NO_SUPPORT)) {
last_error->code == VIR_ERR_NO_SUPPORT) { /* We can emulate --from. */
/* We can emulate --tree --from. */
virFreeError(last_error); virFreeError(last_error);
last_error = NULL; last_error = NULL;
ctl->useSnapshotOld = true; ctl->useSnapshotOld = true;
flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS; flags &= ~VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS;
numsnaps = virDomainSnapshotNum(dom, flags); numsnaps = virDomainSnapshotNum(dom, flags);
} }
} else if (tree) {
numsnaps++;
} }
} else { } else {
numsnaps = virDomainSnapshotNum(dom, flags); numsnaps = virDomainSnapshotNum(dom, flags);
@ -13305,9 +13309,8 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
qsort(&names[0], actual, sizeof(char*), namesorter); qsort(&names[0], actual, sizeof(char*), namesorter);
if (tree) { if (tree || ctl->useSnapshotOld) {
char indentBuf[INDENT_BUFLEN]; parents = vshCalloc(ctl, sizeof(char *), actual);
char **parents = vshCalloc(ctl, sizeof(char *), actual);
for (i = (from && !ctl->useSnapshotOld); i < actual; i++) { for (i = (from && !ctl->useSnapshotOld); i < actual; i++) {
/* free up memory from previous iterations of the loop */ /* free up memory from previous iterations of the loop */
if (snapshot) if (snapshot)
@ -13321,6 +13324,9 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
goto cleanup; goto cleanup;
} }
} }
}
if (tree) {
char indentBuf[INDENT_BUFLEN];
for (i = 0 ; i < actual ; i++) { for (i = 0 ; i < actual ; i++) {
memset(indentBuf, '\0', sizeof indentBuf); memset(indentBuf, '\0', sizeof indentBuf);
if (ctl->useSnapshotOld ? STREQ(names[i], from) : !parents[i]) if (ctl->useSnapshotOld ? STREQ(names[i], from) : !parents[i])
@ -13334,14 +13340,19 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd)
0, 0,
indentBuf); indentBuf);
} }
for (i = 0 ; i < actual ; i++)
VIR_FREE(parents[i]);
VIR_FREE(parents);
ret = true; ret = true;
goto cleanup; goto cleanup;
} else { } else {
if (ctl->useSnapshotOld && descendants) {
/* XXX emulate --descendants as well */
goto cleanup;
}
for (i = 0; i < actual; i++) { for (i = 0; i < actual; i++) {
if (ctl->useSnapshotOld && STRNEQ_NULLABLE(parents[i], from))
continue;
/* free up memory from previous iterations of the loop */ /* free up memory from previous iterations of the loop */
VIR_FREE(parent); VIR_FREE(parent);
VIR_FREE(state); VIR_FREE(state);
@ -13406,9 +13417,13 @@ cleanup:
xmlXPathFreeContext(ctxt); xmlXPathFreeContext(ctxt);
xmlFreeDoc(xml); xmlFreeDoc(xml);
VIR_FREE(doc); VIR_FREE(doc);
for (i = 0; i < actual; i++) for (i = 0; i < actual; i++) {
VIR_FREE(names[i]); VIR_FREE(names[i]);
if (parents)
VIR_FREE(parents[i]);
}
VIR_FREE(names); VIR_FREE(names);
VIR_FREE(parents);
if (dom) if (dom)
virDomainFree(dom); virDomainFree(dom);