[libvirt] [PATCHv4 2/6] virsh: add support for virConnectListAllDomains and clean up cmdList

Peter Krempa pkrempa at redhat.com
Wed Jun 20 13:33:01 UTC 2012


This patch makes use of the newly added api virConnectListAllDomains()
to list domains in virsh.

Virsh now represents lists of domains using an internal structure
vshDomainList. This structure contains the virDomainPtr list as provided
by virConnectListAllDomains() and the count of domains in the list.

For backwards compatiblity, the function vshDomainListCollect was added
that tries to enumerate the domains using the new API and if the API is
not supported falls back to the older approach with the two list
functions.  The helper function also simulates filtering by all
currently supported flags added with virConnectListAllDomains().

This patch also cleans up the "list" command handler to use the new
helpers and adds new command line flags to make use of filtering.
---
Diff to v3:
-Fixed compacting of domain list in fallback filter
-removed redundant filter for active state
-split out re-indentation and rename of namesorter to a separate patch
-renamed functions
-renamed flags
-tweaked docs (typos/grammar)
---
 tools/virsh.c   |  545 ++++++++++++++++++++++++++++++++++++++-----------------
 tools/virsh.pod |   92 +++++++---
 2 files changed, 445 insertions(+), 192 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index 0912781..7ed38dd 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -64,6 +64,7 @@
 #include "util/bitmap.h"
 #include "conf/domain_conf.h"
 #include "virtypedparam.h"
+#include "intprops.h"

 static char *progname;

@@ -490,16 +491,6 @@ _vshStrdup(vshControl *ctl, const char *s, const char *filename, int line)
 #define realloc use_vshRealloc_instead_of_realloc
 #define strdup use_vshStrdup_instead_of_strdup

-static int idsorter(const void *a, const void *b) {
-  const int *ia = (const int *)a;
-  const int *ib = (const int *)b;
-
-  if (*ia > *ib)
-    return 1;
-  else if (*ia < *ib)
-    return -1;
-  return 0;
-}
 static int
 vshNameSorter(const void *a, const void *b)
 {
@@ -990,11 +981,317 @@ static const vshCmdInfo info_list[] = {
     {NULL, NULL}
 };

+/* compare domains, pack NULLed ones at the end*/
+static int
+vshDomainSorter(const void *a, const void *b)
+{
+    virDomainPtr *da = (virDomainPtr *) a;
+    virDomainPtr *db = (virDomainPtr *) b;
+    unsigned int ida;
+    unsigned int idb;
+    unsigned int inactive = (unsigned int) -1;
+
+    if (*da && !*db)
+        return -1;
+
+    if (!*da)
+        return *db != NULL;
+
+    ida = virDomainGetID(*da);
+    idb = virDomainGetID(*db);
+
+    if (ida == inactive && idb == inactive)
+        return strcasecmp(virDomainGetName(*da), virDomainGetName(*db));
+
+    if (ida != inactive && idb != inactive) {
+        if (ida > idb)
+            return 1;
+        else if (ida < idb)
+            return -1;
+    }
+
+    if (ida != inactive)
+        return -1;
+    else
+        return 1;
+}
+
+struct vshDomainList {
+    virDomainPtr *domains;
+    size_t ndomains;
+};
+typedef struct vshDomainList *vshDomainListPtr;
+
+static void
+vshDomainListFree(vshDomainListPtr domlist)
+{
+    int i;
+
+    if (!domlist || !domlist->domains)
+        return;
+
+    for (i = 0; i < domlist->ndomains; i++) {
+        if (domlist->domains[i])
+            virDomainFree(domlist->domains[i]);
+    }
+
+    VIR_FREE(domlist->domains);
+    VIR_FREE(domlist);
+}
+
+#define MATCH(FLAG) (flags & (FLAG))
+static vshDomainListPtr
+vshDomainListCollect(vshControl *ctl, unsigned int flags)
+{
+    vshDomainListPtr list = vshMalloc(ctl, sizeof(*list));
+    int i;
+    int ret;
+    int *ids = NULL;
+    int nids = 0;
+    char **names = NULL;
+    int nnames = 0;
+    virDomainPtr dom;
+    bool success = false;
+    size_t deleted = 0;
+    int persistent;
+    int autostart;
+    int state;
+    int nsnap;
+    int mansave;
+
+    /* try the list with flags support (0.9.13 and later) */
+    if ((ret = virConnectListAllDomains(ctl->conn, &list->domains,
+                                        flags)) >= 0) {
+        list->ndomains = ret;
+        goto finished;
+    }
+
+    /* check if the command is actually supported */
+    if (last_error && last_error->code == VIR_ERR_NO_SUPPORT) {
+        virFreeError(last_error);
+        last_error = NULL;
+        goto fallback;
+    }
+
+    if (last_error && last_error->code ==  VIR_ERR_INVALID_ARG) {
+        /* try the new API again but mask non-guaranteed flags */
+        unsigned int newflags = flags & (VIR_CONNECT_LIST_DOMAINS_ACTIVE |
+                                         VIR_CONNECT_LIST_DOMAINS_INACTIVE);
+
+        virFreeError(last_error);
+        last_error = NULL;
+        if ((ret = virConnectListAllDomains(ctl->conn, &list->domains,
+                                            newflags)) >= 0) {
+            list->ndomains = ret;
+            goto filter;
+        }
+    }
+
+    /* there was an error during the first or second call */
+    vshError(ctl, "%s", _("Failed to list domains"));
+    goto cleanup;
+
+
+fallback:
+    /* fall back to old method (0.9.12 and older) */
+    virResetLastError();
+
+    /* list active domains, if necessary */
+    if (!MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE |
+               VIR_CONNECT_LIST_DOMAINS_INACTIVE) ||
+        MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE)) {
+        if ((nids = virConnectNumOfDomains(ctl->conn)) < 0) {
+            vshError(ctl, "%s", _("Failed to list active domains"));
+            goto cleanup;
+        }
+
+        if (nids) {
+            ids = vshMalloc(ctl, sizeof(int) * nids);
+
+            if ((nids = virConnectListDomains(ctl->conn, ids, nids)) < 0) {
+                vshError(ctl, "%s", _("Failed to list active domains"));
+                goto cleanup;
+            }
+        }
+    }
+
+    if (!MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE |
+               VIR_CONNECT_LIST_DOMAINS_INACTIVE) ||
+        MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE)) {
+        if ((nnames = virConnectNumOfDefinedDomains(ctl->conn)) < 0) {
+            vshError(ctl, "%s", _("Failed to list inactive domains"));
+            goto cleanup;
+        }
+
+        if (nnames) {
+            names = vshMalloc(ctl, sizeof(char *) * nnames);
+
+            if ((nnames = virConnectListDefinedDomains(ctl->conn, names,
+                                                      nnames)) < 0) {
+                vshError(ctl, "%s", _("Failed to list inactive domains"));
+                goto cleanup;
+            }
+        }
+    }
+
+    list->domains = vshMalloc(ctl, sizeof(virDomainPtr) * (nids + nnames));
+    list->ndomains = 0;
+
+    /* get active domains */
+    for (i = 0; i < nids; i++) {
+        if (!(dom = virDomainLookupByID(ctl->conn, ids[i])))
+            continue;
+        list->domains[list->ndomains++] = dom;
+    }
+
+    /* get inactive domains */
+    for (i = 0; i < nnames; i++) {
+        if (!(dom = virDomainLookupByName(ctl->conn, names[i])))
+            continue;
+        list->domains[list->ndomains++] = dom;
+    }
+
+    /* truncate domanis that weren't found */
+    deleted = (nids + nnames) - list->ndomains;
+
+filter:
+    /* filter list the list if the list was acquired by fallback means */
+    for (i = 0; i < list->ndomains; i++) {
+        dom = list->domains[i];
+
+        /* persistence filter */
+        if (MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT |
+                  VIR_CONNECT_LIST_DOMAINS_TRANSIENT)) {
+            if ((persistent = virDomainIsPersistent(dom)) < 0) {
+                vshError(ctl, "%s", _("Failed to get domain persistence info"));
+                goto cleanup;
+            }
+
+            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_PERSISTENT) && persistent) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_TRANSIENT) && !persistent)))
+                goto remove_entry;
+        }
+
+        /* domain state filter */
+        if (MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING |
+                  VIR_CONNECT_LIST_DOMAINS_PAUSED |
+                  VIR_CONNECT_LIST_DOMAINS_SHUTOFF |
+                  VIR_CONNECT_LIST_DOMAINS_OTHER)) {
+            if (virDomainGetState(dom, &state, NULL, 0) < 0) {
+                vshError(ctl, "%s", _("Failed to get domain state"));
+                goto cleanup;
+            }
+
+            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_RUNNING) &&
+                   state == VIR_DOMAIN_RUNNING) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_PAUSED) &&
+                   state == VIR_DOMAIN_PAUSED) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_SHUTOFF) &&
+                   state == VIR_DOMAIN_SHUTOFF) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_OTHER) &&
+                   (state != VIR_DOMAIN_RUNNING &&
+                    state != VIR_DOMAIN_PAUSED &&
+                    state != VIR_DOMAIN_SHUTOFF))))
+                goto remove_entry;
+        }
+
+        /* autostart filter */
+        if (MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART |
+                  VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART)) {
+            if (virDomainGetAutostart(dom, &autostart) < 0) {
+                vshError(ctl, "%s", _("Failed to get domain autostart state"));
+                goto cleanup;
+            }
+
+            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_AUTOSTART) && autostart) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART) && !autostart)))
+                goto remove_entry;
+        }
+
+        /* managed save filter */
+        if (MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE |
+                  VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE)) {
+            if ((mansave = virDomainHasManagedSaveImage(dom, 0)) < 0) {
+                vshError(ctl, "%s",
+                         _("Failed to check for managed save image"));
+                goto cleanup;
+            }
+
+            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE) && mansave) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE) && !mansave)))
+                goto remove_entry;
+        }
+
+        /* snapshot filter */
+        if (MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT |
+                  VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT)) {
+            if ((nsnap = virDomainSnapshotNum(dom, 0)) < 0) {
+                vshError(ctl, "%s", _("Failed to get snapshot count"));
+                goto cleanup;
+            }
+            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT) && nsnap > 0) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT) && nsnap == 0)))
+                goto remove_entry;
+        }
+
+        /* the domain matched all filters, it may stay */
+        continue;
+
+remove_entry:
+        /* the domain has to be removed as it failed one of the filters */
+        virDomainFree(list->domains[i]);
+        list->domains[i] = NULL;
+        deleted++;
+    }
+
+finished:
+    /* sort the list */
+    if (list->domains && list->ndomains)
+        qsort(list->domains, list->ndomains, sizeof(*list->domains),
+              vshDomainSorter);
+
+    /* truncate the list if filter simulation deleted entries */
+    if (deleted)
+        VIR_SHRINK_N(list->domains, list->ndomains, deleted);
+
+    success = true;
+
+cleanup:
+    for (i = 0; i < nnames; i++)
+        VIR_FREE(names[i]);
+
+    if (!success) {
+        vshDomainListFree(list);
+        list = NULL;
+    }
+
+    VIR_FREE(names);
+    VIR_FREE(ids);
+    return list;
+}
+#undef MATCH
+
+
 static const vshCmdOptDef opts_list[] = {
     {"inactive", VSH_OT_BOOL, 0, N_("list inactive domains")},
     {"all", VSH_OT_BOOL, 0, N_("list inactive & active domains")},
     {"transient", VSH_OT_BOOL, 0, N_("list transient domains")},
     {"persistent", VSH_OT_BOOL, 0, N_("list persistent domains")},
+    {"with-snapshot", VSH_OT_BOOL, 0,
+     N_("list domains with existing snapshot")},
+    {"without-snapshot", VSH_OT_BOOL, 0,
+     N_("list domains without a snapshot")},
+    {"state-running", VSH_OT_BOOL, 0, N_("list domains in running state")},
+    {"state-paused", VSH_OT_BOOL, 0, N_("list domains in paused state")},
+    {"state-shutoff", VSH_OT_BOOL, 0, N_("list domains in shutoff state")},
+    {"state-other", VSH_OT_BOOL, 0, N_("list domains in other states")},
+    {"autostart", VSH_OT_BOOL, 0, N_("list domains with autostart enabled")},
+    {"no-autostart", VSH_OT_BOOL, 0,
+     N_("list domains with autostart disabled")},
+    {"with-managed-save", VSH_OT_BOOL, 0,
+     N_("list domains with managed save state")},
+    {"without-managed-save", VSH_OT_BOOL, 0,
+     N_("list domains without managed save")},
     {"uuid", VSH_OT_BOOL, 0, N_("list uuid's only")},
     {"name", VSH_OT_BOOL, 0, N_("list domain names only")},
     {"table", VSH_OT_BOOL, 0, N_("list table (default)")},
@@ -1005,38 +1302,52 @@ static const vshCmdOptDef opts_list[] = {
 };


+#define FILTER(NAME, FLAG)              \
+    if (vshCommandOptBool(cmd, NAME))   \
+        flags |= (FLAG)
 static bool
 cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
 {
-    bool inactive = vshCommandOptBool(cmd, "inactive");
-    bool all = vshCommandOptBool(cmd, "all");
-    bool active = !inactive || all;
-    int *ids = NULL, maxid = 0, i;
-    char **names = NULL;
-    int maxname = 0;
     bool managed = vshCommandOptBool(cmd, "managed-save");
     bool optTitle = vshCommandOptBool(cmd, "title");
     bool optTable = vshCommandOptBool(cmd, "table");
     bool optUUID = vshCommandOptBool(cmd, "uuid");
     bool optName = vshCommandOptBool(cmd, "name");
-    bool optPersistent = vshCommandOptBool(cmd, "persistent");
-    bool optTransient = vshCommandOptBool(cmd, "transient");
-    bool persistUsed = true;
-    virDomainPtr dom = NULL;
+    int i;
     char *title;
     char uuid[VIR_UUID_STRING_BUFLEN];
     int state;
-    int persistent;
     bool ret = false;
+    vshDomainListPtr list = NULL;
+    virDomainPtr dom;
+    char id_buf[INT_BUFSIZE_BOUND(unsigned int)];
+    unsigned int id;
+    unsigned int flags = VIR_CONNECT_LIST_DOMAINS_ACTIVE;

-    inactive |= all;
+    /* construct filter flags */
+    if (vshCommandOptBool(cmd, "inactive"))
+        flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE;

-    /* process arguments */
-    if (!optPersistent && !optTransient) {
-        optPersistent = true;
-        optTransient = true;
-        persistUsed = false;
-    }
+    if (vshCommandOptBool(cmd, "all"))
+        flags = VIR_CONNECT_LIST_DOMAINS_INACTIVE |
+                VIR_CONNECT_LIST_DOMAINS_ACTIVE;
+
+    FILTER("persistent", VIR_CONNECT_LIST_DOMAINS_PERSISTENT);
+    FILTER("transient",  VIR_CONNECT_LIST_DOMAINS_TRANSIENT);
+
+    FILTER("with-managed-save",    VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE);
+    FILTER("without-managed-save", VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE);
+
+    FILTER("autostart",    VIR_CONNECT_LIST_DOMAINS_AUTOSTART);
+    FILTER("no-autostart", VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART);
+
+    FILTER("with-snapshot",    VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT);
+    FILTER("without-snapshot", VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT);
+
+    FILTER("state-running", VIR_CONNECT_LIST_DOMAINS_RUNNING);
+    FILTER("state-paused",  VIR_CONNECT_LIST_DOMAINS_PAUSED);
+    FILTER("state-shutoff", VIR_CONNECT_LIST_DOMAINS_SHUTOFF);
+    FILTER("state-other",   VIR_CONNECT_LIST_DOMAINS_OTHER);

     if (optTable + optName + optUUID > 1) {
         vshError(ctl, "%s",
@@ -1051,169 +1362,69 @@ cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
     if (!vshConnectionUsability(ctl, ctl->conn))
         return false;

-    if (active) {
-        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, maxid)) < 0) {
-                vshError(ctl, "%s", _("Failed to list active domains"));
-                goto cleanup;
-            }
-
-            qsort(ids, maxid, sizeof(int), idsorter);
-        }
-    }
-
-    if (inactive) {
-        maxname = virConnectNumOfDefinedDomains(ctl->conn);
-        if (maxname < 0) {
-            vshError(ctl, "%s", _("Failed to list inactive domains"));
-            goto cleanup;
-        }
-        if (maxname) {
-            names = vshMalloc(ctl, sizeof(char *) * maxname);
-
-            if ((maxname = virConnectListDefinedDomains(ctl->conn,
-                                                        names,
-                                                        maxname)) < 0) {
-                vshError(ctl, "%s", _("Failed to list inactive domains"));
-                goto cleanup;
-            }
-
-            qsort(&names[0], maxname, sizeof(char*), vshNameSorter);
-        }
-    }
+    if (!(list = vshDomainListCollect(ctl, flags)))
+        goto cleanup;

     /* print table header in legacy mode */
     if (optTable) {
-        if (optTitle) {
+        if (optTitle)
             vshPrintExtra(ctl, " %-5s %-30s %-10s %-20s\n%s\n",
                           _("Id"), _("Name"), _("State"), _("Title"),
                           "-----------------------------------------"
                           "-----------------------------------------");
-        } else {
+        else
             vshPrintExtra(ctl, " %-5s %-30s %s\n%s\n",
                           _("Id"), _("Name"), _("State"),
                           "-----------------------------------------"
                           "-----------");
-        }
     }

-    for (i = 0; i < maxid; i++) {
-         dom = virDomainLookupByID(ctl->conn, ids[i]);
-
-        /* this kind of work with domains is not atomic operation */
-        if (!dom)
-            continue;
+    for (i = 0; i < list->ndomains; i++) {
+        dom = list->domains[i];
+        id = virDomainGetID(dom);
+        if (id != (unsigned int) -1)
+            snprintf(id_buf, sizeof(id_buf), "%d", id);
+        else
+            ignore_value(virStrcpyStatic(id_buf, "-"));

-        if (persistUsed) {
-            persistent = virDomainIsPersistent(dom);
-            if (persistent < 0) {
-                vshError(ctl, "%s",
-                         _("Failed to determine domain's persistent state"));
-                goto cleanup;
-            }
+        state = vshDomainState(ctl, dom, NULL);
+        if (optTable && managed && state == VIR_DOMAIN_SHUTOFF &&
+            virDomainHasManagedSaveImage(dom, 0) > 0)
+            state = -2;

-            if (!(persistent ? optPersistent : optTransient)) {
-                virDomainFree(dom);
-                dom = NULL;
-                continue;
-            }
-       }
-
-       if (optTable) {
-           if (optTitle) {
-               if (!(title = vshGetDomainDescription(ctl, dom, true, 0)))
-                   goto cleanup;
-
-               vshPrint(ctl, " %-5d %-30s %-10s %-20s\n",
-                        virDomainGetID(dom),
-                        virDomainGetName(dom),
-                        _(vshDomainStateToString(vshDomainState(ctl, dom, NULL))),
-                        title);
-               VIR_FREE(title);
-           } else {
-               vshPrint(ctl, " %-5d %-30s %s\n",
-                        virDomainGetID(dom),
-                        virDomainGetName(dom),
-                        _(vshDomainStateToString(vshDomainState(ctl, dom, NULL))));
-           }
-       } else if (optUUID) {
-           if (virDomainGetUUIDString(dom, uuid) < 0) {
-               vshError(ctl, "%s",
-                        _("Failed to get domain's UUID"));
-               goto cleanup;
-           }
-           vshPrint(ctl, "%s\n", uuid);
-       } else if (optName) {
-           vshPrint(ctl, "%s\n", virDomainGetName(dom));
-       }
-
-       virDomainFree(dom);
-       dom = NULL;
-    }
-
-    if (optPersistent) {
-        for (i = 0; i < maxname; i++) {
-            dom = virDomainLookupByName(ctl->conn, names[i]);
-
-            /* this kind of work with domains is not atomic operation */
-            if (!dom)
-                continue;
+        if (optTable) {
+            if (optTitle) {
+                if (!(title = vshGetDomainDescription(ctl, dom, true, 0)))
+                    goto cleanup;

-            if (optTable) {
-                state = vshDomainState(ctl, dom, NULL);
-                if (managed && state == VIR_DOMAIN_SHUTOFF &&
-                    virDomainHasManagedSaveImage(dom, 0) > 0)
-                    state = -2;
-
-                if (optTitle) {
-                    if (!(title = vshGetDomainDescription(ctl, dom, true, 0)))
-                        goto cleanup;
-
-                    vshPrint(ctl, " %-5s %-30s %-10s %-20s\n",
-                             "-",
-                             names[i],
-                             state == -2 ? _("saved") : _(vshDomainStateToString(state)),
-                             title);
-                    VIR_FREE(title);
-                } else {
-                    vshPrint(ctl, " %-5s %-30s %s\n",
-                             "-",
-                             names[i],
-                             state == -2 ? _("saved") : _(vshDomainStateToString(state)));
-                }
-           } else if (optUUID) {
-               if (virDomainGetUUIDString(dom, uuid) < 0) {
-                   vshError(ctl, "%s",
-                            _("Failed to get domain's UUID"));
-                   goto cleanup;
-               }
-               vshPrint(ctl, "%s\n", uuid);
-           } else if (optName) {
-               vshPrint(ctl, "%s\n", names[i]);
-           }
+                vshPrint(ctl, " %-5s %-30s %-10s %-20s\n", id_buf,
+                         virDomainGetName(dom),
+                         state == -2 ? _("saved") : _(vshDomainStateToString(state)),
+                         title);

-           virDomainFree(dom);
-           dom = NULL;
+                VIR_FREE(title);
+            } else {
+                vshPrint(ctl, " %-5s %-30s %s\n", id_buf,
+                         virDomainGetName(dom),
+                         state == -2 ? _("saved") : _(vshDomainStateToString(state)));
+            }
+        } else if (optUUID) {
+            if (virDomainGetUUIDString(dom, uuid) < 0) {
+                vshError(ctl, "%s", _("Failed to get domain's UUID"));
+                goto cleanup;
+            }
+            vshPrint(ctl, "%s\n", uuid);
+        } else if (optName) {
+            vshPrint(ctl, "%s\n", virDomainGetName(dom));
         }
     }

     ret = true;
 cleanup:
-    if (dom)
-        virDomainFree(dom);
-    VIR_FREE(ids);
-    for (i = 0; i < maxname; i++)
-        VIR_FREE(names[i]);
-    VIR_FREE(names);
+    vshDomainListFree(list);
     return ret;
 }
+#undef FILTER

 /*
  * "desc" command for managing domain description and title
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 839c156..f83a29d 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -306,9 +306,15 @@ The XML also show the NUMA topology information if available.

 Inject NMI to the guest.

-=item B<list> [I<--inactive> | I<--all>] [I<--managed-save>] [I<--title>]
-              { [I<--table>] | I<--name> | I<--uuid> } [I<--persistent>]
-              [I<--transient>]
+=item B<list> [I<--inactive> | I<--all>]
+              [I<--managed-save>] [I<--title>]
+              { [I<--table>] | I<--name> | I<--uuid> }
+              [I<--persistent>] [I<--transient>]
+              [I<--with-managed-save>] [I<--without-managed-save>]
+              [I<--autostart>] [I<--no-autostart>]
+              [I<--with-snapshot>] [I<--without-snapshot>]
+              [I<--state-running>] [I<--state-paused>]
+              [I<--state-shutoff>] [I<--state-other>]

 Prints information about existing domains.  If no options are
 specified it prints out information about running domains.
@@ -316,13 +322,10 @@ specified it prints out information about running domains.
 An example format for the list is as follows:

 B<virsh> list
- Id Name                 State
-
-----------------------------------
-
-  0 Domain-0             running
-  2 fedora               paused
-
+  Id    Name                           State
+ ----------------------------------------------------
+  0     Domain-0                       running
+  2     fedora                         paused

 Name is the name of the domain.  ID the domain numeric id.
 State is the run state (see below).
@@ -380,11 +383,56 @@ into s3 state.

 =back

-If I<--managed-save> is specified, then domains that have managed save
-state (only possible if they are in the B<shut off> state, so you need to
-specify I<--inactive> or I<--all> to actually list them) will instead
-show as B<saved> in the listing. This flag is usable only with the
-default I<--table> output.
+Normally only active domains are listed. To list inactive domains specify
+I<--inactive> or I<--all> to list both active and inactive domains.
+
+To filter the list of domains present on the hypervisor you may specify one or
+more of filtering flags supported by the B<list> command.  These flags are
+grouped by function. Specifying one or more flags from a group enables the
+filter group. Supported filtering flags and groups:
+
+=over 4
+
+=item B<Persistence>
+
+Flag I<--persistent> is used to include persistent domains in the returned
+list. To include transient domains specify I<--transient>.
+
+=item B<Existence of managed save image>
+
+To list domains having a managed save image specify flag
+I<--with-managed-save>. For domains that don't have a managed save image
+specify I<--without-managed-save>.
+
+=item B<Domain state>
+
+The following filter flags select a domain by its state:
+I<--state-running> for running domains, I<--state-paused>  for paused domains,
+I<--state-shutoff> for turned off domains and I<--state-other> for all
+other states as a fallback.
+
+=item B<Autostarting domains>
+
+To list autostarting domains use the flag I<--autostart>. To list domains with
+this feature disabled use I<--no-autostart>.
+
+=item B<Snapshot existence>
+
+Domains that have snapshot images can be listed using flag I<--with-snapshot>,
+domains without a snapshot I<--without-snapshot>.
+
+=back
+
+When talking to older servers, this command is forced to use a series of API
+calls with an inherent race, where a domain might not be listed or might appear
+more than once if it changed state between calls while the list was being
+collected.  Newer servers do not have this problem.
+
+If I<--managed-save> is specified, then domains that have managed save state
+(only possible if they are in the B<shut off> state, so you need to specify
+I<--inactive> or I<--all> to actually list them) will instead show as B<saved>
+in the listing. This flag is usable only with the default I<--table> output.
+Note that this flag does not filter the list of domains.

 If I<--name> is specified, domain names are printed instead of the table
 formatted one per line. If I<--uuid> is specified domain's UUID's are printed
@@ -392,12 +440,6 @@ instead of names. Flag I<--table> specifies that the legacy table-formatted
 output should be used. This is the default. All of these are mutually
 exclusive.

-Flag I<--persistent> specifies that persistent domains should be printed.
-Similarly I<--transient> enables output of transient domains. These flags
-may be combined. Default behavior is as though both were specified. (Note that
-if any of these flags is specified, the check for the persistence state is done
-and may fail. If none of these flags is specified, the check is skipped.)
-
 If I<--title> is specified, then the short domain description (title) is
 printed in an extra column. This flag is usable only with the default
 I<--table> output.
@@ -405,10 +447,10 @@ I<--table> output.
 Example:

 B<virsh> list --title
- Id Name                 State      Title
- -----------------------------------------------
-  0 Domain-0             running    Mailserver 1
-  2 fedora               paused
+  Id    Name                           State      Title
+ --------------------------------------------------------------------------
+  0     Domain-0                       running    Mailserver 1
+  2     fedora                         paused

 =item B<freecell> [{ [I<--cellno>] B<cellno> | I<--all> }]

-- 
1.7.8.6




More information about the libvir-list mailing list