diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index c991dfcde4..5d30bbbddb 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -2701,6 +2701,8 @@ typedef enum { listing a snapshot */ VIR_DOMAIN_SNAPSHOT_LIST_METADATA = (1 << 1), /* Filter by snapshots which have metadata */ + VIR_DOMAIN_SNAPSHOT_LIST_LEAVES = (1 << 2), /* Filter by snapshots + with no children */ } virDomainSnapshotListFlags; /* Return the number of snapshots for this domain */ diff --git a/src/libvirt.c b/src/libvirt.c index f07c720bf2..35eb6b4863 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -15969,7 +15969,10 @@ error: * Provides the number of domain snapshots for this domain. * * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_ROOTS, then the result is - * filtered to the number of snapshots that have no parents. + * filtered to the number of snapshots that have no parents. Likewise, + * if @flags includes VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, then the result is + * filtered to the number of snapshots that have no children. Both flags + * can be used together to find unrelated snapshots. * * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_METADATA, then the result is * the number of snapshots that also include metadata that would prevent @@ -16020,7 +16023,10 @@ error: * virDomainSnapshotNum() with the same @flags. * * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_ROOTS, then the result is - * filtered to the number of snapshots that have no parents. + * filtered to the number of snapshots that have no parents. Likewise, + * if @flags includes VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, then the result is + * filtered to the number of snapshots that have no children. Both flags + * can be used together to find unrelated snapshots. * * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_METADATA, then the result is * the number of snapshots that also include metadata that would prevent @@ -16077,6 +16083,9 @@ error: * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS, then the result * includes all descendants, otherwise it is limited to direct children. * + * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, then the result is + * filtered to the number of snapshots that have no children. + * * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_METADATA, then the result is * the number of snapshots that also include metadata that would prevent * the removal of the last reference to a domain; this value will either @@ -16129,6 +16138,9 @@ error: * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS, then the result * includes all descendants, otherwise it is limited to direct children. * + * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_LEAVES, then the result is + * filtered to the number of snapshots that have no children. + * * If @flags includes VIR_DOMAIN_SNAPSHOT_LIST_METADATA, then the result is * the number of snapshots that also include metadata that would prevent * the removal of the last reference to a domain; this value will either diff --git a/tools/virsh.c b/tools/virsh.c index bcf06034f6..0624bd85a1 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -13180,6 +13180,7 @@ static const vshCmdOptDef opts_snapshot_list[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"parent", VSH_OT_BOOL, 0, N_("add a column showing parent snapshot")}, {"roots", VSH_OT_BOOL, 0, N_("list only snapshots without parents")}, + {"leaves", VSH_OT_BOOL, 0, N_("list only snapshots without children")}, {"metadata", VSH_OT_BOOL, 0, N_("list only snapshots that have metadata that would prevent undefine")}, {"tree", VSH_OT_BOOL, 0, N_("list snapshots in a tree")}, @@ -13214,6 +13215,7 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) char timestr[100]; struct tm time_info; bool tree = vshCommandOptBool(cmd, "tree"); + bool leaves = vshCommandOptBool(cmd, "leaves"); const char *from = NULL; virDomainSnapshotPtr start = NULL; int start_index = -1; @@ -13255,6 +13257,14 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) } flags |= VIR_DOMAIN_SNAPSHOT_LIST_ROOTS; } + if (leaves) { + if (tree) { + vshError(ctl, "%s", + _("--leaves and --tree are mutually exclusive")); + return false; + } + flags |= VIR_DOMAIN_SNAPSHOT_LIST_LEAVES; + } if (vshCommandOptBool(cmd, "metadata")) { flags |= VIR_DOMAIN_SNAPSHOT_LIST_METADATA; @@ -13271,6 +13281,7 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) if (ctl->useSnapshotOld || last_error->code == VIR_ERR_NO_SUPPORT) { /* We can emulate --from. */ + /* XXX can we also emulate --leaves? */ virFreeError(last_error); last_error = NULL; ctl->useSnapshotOld = true; @@ -13284,6 +13295,7 @@ cmdSnapshotList(vshControl *ctl, const vshCmd *cmd) numsnaps = virDomainSnapshotNum(dom, flags); /* Fall back to simulation if --roots was unsupported. */ + /* XXX can we also emulate --leaves? */ if (numsnaps < 0 && last_error->code == VIR_ERR_INVALID_ARG && (flags & VIR_DOMAIN_SNAPSHOT_LIST_ROOTS)) { virFreeError(last_error); diff --git a/tools/virsh.pod b/tools/virsh.pod index d0b79379a9..c68d0d58ca 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -1980,7 +1980,8 @@ snapshots, such as internal snapshots within a single qcow2 file, are accessible only from the original name. =item B I [{I<--parent> | I<--roots> | I<--tree>}] -[I<--metadata>] [{[I<--from>] B | I<--current>} [I<--descendants>]] +[{[I<--from>] B | I<--current>} [I<--descendants>]] +[I<--metadata>] [I<--leaves>] List all of the available snapshots for the given domain, defaulting to show columns for the snapshot name, creation time, and domain state. @@ -1999,6 +2000,10 @@ I<--descendants> is also present. When used with I<--tree>, the use of I<--descendants> is implied. This option is not compatible with I<--roots>. +If I<--leaves> is specified, the list will be filtered to just +snapshots that have no children. This option is not compatible +with I<--tree>. + If I<--metadata> is specified, the list will be filtered to just snapshots that involve libvirt metadata, and thus would prevent B of a persistent domain, or be lost on B of