[libvirt] [PATCHv3 02/12] virsh: add support for virConnectListAllDomains and clean up cmdList

Peter Krempa pkrempa at redhat.com
Mon Jun 11 10:33:57 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 function vshDomList 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 v2:
- moved this patch right after API implementation to make testing fallback easier
- added support for all filtering flags both in fallback code and in "list" command
- fixed messed up syntax check silencing :)
- fixed spelling errors but probably introduced a ton of new as I've added new docs
---
 tools/virsh.c   |  555 ++++++++++++++++++++++++++++++++++++++-----------------
 tools/virsh.pod |   91 +++++++---
 2 files changed, 449 insertions(+), 197 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index abcfbff..8d86cb0 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,22 +491,307 @@ _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;
+static int
+namesorter(const void *a, const void *b)
+{
+    const char **sa = (const char**)a;
+    const char **sb = (const char**)b;

-  if (*ia > *ib)
-    return 1;
-  else if (*ia < *ib)
-    return -1;
-  return 0;
+    /* User visible sort, so we want locale-specific case comparison. */
+    return strcasecmp(*sa, *sb);
+}
+
+static int
+domsorter(const void *a, const void *b)
+{
+    virDomainPtr *da = (virDomainPtr *) a;
+    virDomainPtr *db = (virDomainPtr *) b;
+    unsigned int ida = virDomainGetID(*da);
+    unsigned int idb = virDomainGetID(*db);
+    unsigned int inactive = (unsigned int) -1;
+
+    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;
+    int ndomains;
+};
+typedef struct vshDomainList *vshDomainListPtr;
+
+#define MATCH(FLAG) (flags & (FLAG))
+static int
+vshDomList(vshControl *ctl, vshDomainListPtr domlist, unsigned int flags)
+{
+    int rv = -1;
+    virErrorPtr err = NULL;
+    int i;
+    int *ids = NULL;
+    int nids = 0;
+    char **names = NULL;
+    int nnames = 0;
+    virDomainPtr dom;
+    virDomainPtr *doms = NULL;
+    int ndoms = 0;
+    int count = 0;
+    int active;
+    int persistent;
+    int autostart;
+    int state;
+    int nsnap;
+    int mansave;
+
+    domlist->domains = NULL;
+    domlist->ndomains = 0;
+
+    /* try the list with flags support */
+    if ((ndoms = virConnectListAllDomains(ctl->conn, &doms, flags)) >= 0) {
+        domlist->ndomains = ndoms;
+        domlist->domains = doms;
+        doms = NULL;
+        goto finished;
+    }
+
+    /* check if the command is actualy supported */
+    if ((err = virGetLastError()) &&
+        err->code == VIR_ERR_NO_SUPPORT)
+        goto fallback;
+
+    if ((err= virGetLastError()) &&
+        err->code ==  VIR_ERR_INVALID_ARG) {
+        /* try again the new API but without flags this time */
+        if ((ndoms = virConnectListAllDomains(ctl->conn, &doms, 0)) >= 0)
+            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 */
+    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;
+            }
+        }
+    }
+
+    doms = vshMalloc(ctl, sizeof(virDomainPtr) * (nids + nnames));
+    ndoms = 0;
+
+    /* get active domains */
+    for (i = 0; i < nids; i++) {
+        if (!(dom = virDomainLookupByID(ctl->conn, ids[i])))
+            continue;
+        doms[ndoms++] = dom;
+    }
+
+    /* get inctive domains */
+    for (i = 0; i < nnames; i++) {
+        if (!(dom = virDomainLookupByName(ctl->conn, names[i])))
+            continue;
+        doms[ndoms++] = dom;
+    }
+
+filter:
+    /* filter list the list if the list was acquired by fallback means */
+    for (i = 0; i < ndoms; i++) {
+        dom = doms[i];
+
+        /* active state filter */
+        if (MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE |
+                  VIR_CONNECT_LIST_DOMAINS_INACTIVE)) {
+            if ((active = virDomainIsActive(dom)) < 0) {
+                vshError(ctl, "%s", _("Failed to get domain active state"));
+                goto cleanup;
+            }
+
+            if (!((MATCH(VIR_CONNECT_LIST_DOMAINS_ACTIVE) && active) ||
+                  (MATCH(VIR_CONNECT_LIST_DOMAINS_INACTIVE) && !active)))
+                goto remove_entry;
+        }
+
+        /* 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, pack them at the front */
+        doms[count++] = dom;
+        continue;
+
+remove_entry:
+        /* the domain has to be removed as it failed one of the filters */
+        virDomainFree(doms[i]);
+        doms[i] = NULL;
+    }
+
+    /* we're shortening the array, so it's safe to ignore value */
+    ignore_value(VIR_REALLOC_N(doms, count));
+
+    domlist->domains = doms;
+    domlist->ndomains = count;
+    doms = NULL;
+
+finished:
+    /* sort the list */
+    if (domlist->domains && domlist->ndomains > 0)
+        qsort(domlist->domains, domlist->ndomains,
+              sizeof(*domlist->domains), domsorter);
+
+    rv = domlist->ndomains;
+
+cleanup:
+    for (i = 0; i < nnames; i++)
+        VIR_FREE(names[i]);
+    if (doms) {
+        for (i = 0; i < ndoms; i++) {
+            if (doms[i])
+                virDomainFree(doms[i]);
+        }
+    }
+    VIR_FREE(doms);
+    VIR_FREE(names);
+    VIR_FREE(ids);
+    return rv;
 }
-static int namesorter(const void *a, const void *b) {
-  const char **sa = (const char**)a;
-  const char **sb = (const char**)b;
+#undef MATCH
+
+static void
+vshDomListFree(vshDomainListPtr domlist)
+{
+    int i;
+
+    if (!domlist || !domlist->domains)
+        return;

-  /* User visible sort, so we want locale-specific case comparison.  */
-  return strcasecmp(*sa, *sb);
+    for (i = 0; i < domlist->ndomains; i++) {
+        if (domlist->domains[i])
+            virDomainFree(domlist->domains[i]);
+    }
+
+    domlist->ndomains = 0;
+    VIR_FREE(domlist->domains);
 }

 static double
@@ -977,6 +1263,21 @@ static const vshCmdOptDef opts_list[] = {
     {"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")},
+    {"snapshot-yes", VSH_OT_BOOL, 0,
+     N_("list domains with existing snapshot")},
+    {"snapshot-no", 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-yes", VSH_OT_BOOL, 0,
+     N_("list domains with autostart enabled")},
+    {"autostart-no", VSH_OT_BOOL, 0,
+     N_("list domains with autostart disabled")},
+    {"managedsave-yes", VSH_OT_BOOL, 0,
+     N_("list domains with managed save state")},
+    {"managedsave-no", 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)")},
@@ -987,38 +1288,50 @@ 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;
+    struct vshDomainList list;
+    char id[INT_BUFSIZE_BOUND(unsigned int)];
+    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("managedsave-yes", VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE);
+    FILTER("managedsave-no",  VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE);
+
+    FILTER("autostart-yes", VIR_CONNECT_LIST_DOMAINS_AUTOSTART);
+    FILTER("autostart-no",  VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART);
+
+    FILTER("snapshot-yes", VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT);
+    FILTER("snapshot-no",  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",
@@ -1033,169 +1346,67 @@ 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*), namesorter);
-        }
-    }
+    if (vshDomList(ctl, &list, flags) < 0)
+        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++) {
+        if (virDomainGetID(list.domains[i]) != (unsigned int) -1)
+            snprintf(id, sizeof(id), "%d", virDomainGetID(list.domains[i]));
+        else
+            ignore_value(virStrcpyStatic(id, "-"));

-        if (persistUsed) {
-            persistent = virDomainIsPersistent(dom);
-            if (persistent < 0) {
-                vshError(ctl, "%s",
-                         _("Failed to determine domain's persistent state"));
-                goto cleanup;
-            }
+        state = vshDomainState(ctl, list.domains[i], NULL);
+        if (optTable && managed && state == VIR_DOMAIN_SHUTOFF &&
+            virDomainHasManagedSaveImage(list.domains[i], 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, list.domains[i], 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,
+                         virDomainGetName(list.domains[i]),
+                         state == -2 ? _("saved") : _(vshDomainStateToString(state)),
+                         title);

-           virDomainFree(dom);
-           dom = NULL;
+                VIR_FREE(title);
+            } else {
+                vshPrint(ctl, " %-5s %-30s %s\n", id,
+                         virDomainGetName(list.domains[i]),
+                         state == -2 ? _("saved") : _(vshDomainStateToString(state)));
+            }
+        } else if (optUUID) {
+            if (virDomainGetUUIDString(list.domains[i], 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(list.domains[i]));
         }
     }

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

 /*
  * "desc" command for managing domain description and title
diff --git a/tools/virsh.pod b/tools/virsh.pod
index ef71717..7e7309d 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<--managedsave-yes>] [I<--managedsave-no>]
+              [I<--autostart-yes>] [I<--autostart-no>]
+              [I<--snapshot-yes>] [I<--snapshot-no>]
+              [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,55 @@ 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 of 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<--managedsave-yes>.
+For domains that don't have a managed save image specify I<--managedsave-no>.
+
+=item B<Domain state>
+
+Following filter flags to select domains by its state are available:
+I<--state-running> for runnign 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-yes>. To list domains
+with this feature disabled use I<--autostart-no>.
+
+=item B<Snapshot existence>
+
+Domains that have snapshot images can be listed using flagI<--snapshot-yes>,
+domains without a snapshot I<--snapshot-no>.
+
+=back
+
+First attempt to acquire the domain list is done by the non-racy listing API.
+If this API is not available for the current connection the list is constructed
+using fallback code that might miss domains transitioning states when the
+fallback code is executed.
+
+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 +439,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 +446,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.3.4




More information about the libvir-list mailing list