Пример #1
0
static bool
virshConnectionUsability(vshControl *ctl, virConnectPtr conn)
{
    if (!conn ||
        virConnectIsAlive(conn) == 0) {
        vshError(ctl, "%s", _("no valid connection"));
        return false;
    }

    /* The connection is considered dead only if
     * virConnectIsAlive() successfuly says so.
     */
    vshResetLibvirtError();

    return true;
}
Пример #2
0
static virshNetworkListPtr
virshNetworkListCollect(vshControl *ctl,
                        unsigned int flags)
{
    virshNetworkListPtr list = vshMalloc(ctl, sizeof(*list));
    size_t i;
    int ret;
    char **names = NULL;
    virNetworkPtr net;
    bool success = false;
    size_t deleted = 0;
    int persistent;
    int autostart;
    int nActiveNets = 0;
    int nInactiveNets = 0;
    int nAllNets = 0;
    virshControlPtr priv = ctl->privData;

    /* try the list with flags support (0.10.2 and later) */
    if ((ret = virConnectListAllNetworks(priv->conn,
                                         &list->nets,
                                         flags)) >= 0) {
        list->nnets = ret;
        goto finished;
    }

    /* check if the command is actually supported */
    if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
        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_NETWORKS_ACTIVE |
                                         VIR_CONNECT_LIST_NETWORKS_INACTIVE);

        vshResetLibvirtError();
        if ((ret = virConnectListAllNetworks(priv->conn, &list->nets,
                                             newflags)) >= 0) {
            list->nnets = ret;
            goto filter;
        }
    }

    /* there was an error during the first or second call */
    vshError(ctl, "%s", _("Failed to list networks"));
    goto cleanup;


 fallback:
    /* fall back to old method (0.10.1 and older) */
    vshResetLibvirtError();

    /* Get the number of active networks */
    if (!VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
        VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)) {
        if ((nActiveNets = virConnectNumOfNetworks(priv->conn)) < 0) {
            vshError(ctl, "%s", _("Failed to get the number of active networks"));
            goto cleanup;
        }
    }

    /* Get the number of inactive networks */
    if (!VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
        VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_INACTIVE)) {
        if ((nInactiveNets = virConnectNumOfDefinedNetworks(priv->conn)) < 0) {
            vshError(ctl, "%s", _("Failed to get the number of inactive networks"));
            goto cleanup;
        }
    }

    nAllNets = nActiveNets + nInactiveNets;

    if (nAllNets == 0)
         return list;

    names = vshMalloc(ctl, sizeof(char *) * nAllNets);

    /* Retrieve a list of active network names */
    if (!VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
        VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)) {
        if (virConnectListNetworks(priv->conn,
                                   names, nActiveNets) < 0) {
            vshError(ctl, "%s", _("Failed to list active networks"));
            goto cleanup;
        }
    }

    /* Add the inactive networks to the end of the name list */
    if (!VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_ACTIVE) ||
        VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_ACTIVE)) {
        if (virConnectListDefinedNetworks(priv->conn,
                                          &names[nActiveNets],
                                          nInactiveNets) < 0) {
            vshError(ctl, "%s", _("Failed to list inactive networks"));
            goto cleanup;
        }
    }

    list->nets = vshMalloc(ctl, sizeof(virNetworkPtr) * (nAllNets));
    list->nnets = 0;

    /* get active networks */
    for (i = 0; i < nActiveNets; i++) {
        if (!(net = virNetworkLookupByName(priv->conn, names[i])))
            continue;
        list->nets[list->nnets++] = net;
    }

    /* get inactive networks */
    for (i = 0; i < nInactiveNets; i++) {
        if (!(net = virNetworkLookupByName(priv->conn, names[i])))
            continue;
        list->nets[list->nnets++] = net;
    }

    /* truncate networks that weren't found */
    deleted = nAllNets - list->nnets;

 filter:
    /* filter list the list if the list was acquired by fallback means */
    for (i = 0; i < list->nnets; i++) {
        net = list->nets[i];

        /* persistence filter */
        if (VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_PERSISTENT)) {
            if ((persistent = virNetworkIsPersistent(net)) < 0) {
                vshError(ctl, "%s", _("Failed to get network persistence info"));
                goto cleanup;
            }

            if (!((VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_PERSISTENT) && persistent) ||
                  (VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_TRANSIENT) && !persistent)))
                goto remove_entry;
        }

        /* autostart filter */
        if (VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_FILTERS_AUTOSTART)) {
            if (virNetworkGetAutostart(net, &autostart) < 0) {
                vshError(ctl, "%s", _("Failed to get network autostart state"));
                goto cleanup;
            }

            if (!((VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_AUTOSTART) && autostart) ||
                  (VSH_MATCH(VIR_CONNECT_LIST_NETWORKS_NO_AUTOSTART) && !autostart)))
                goto remove_entry;
        }
        /* the pool matched all filters, it may stay */
        continue;

 remove_entry:
        /* the pool has to be removed as it failed one of the filters */
        virNetworkFree(list->nets[i]);
        list->nets[i] = NULL;
        deleted++;
    }

 finished:
    /* sort the list */
    if (list->nets && list->nnets)
        qsort(list->nets, list->nnets,
              sizeof(*list->nets), virshNetworkSorter);

    /* truncate the list if filter simulation deleted entries */
    if (deleted)
        VIR_SHRINK_N(list->nets, list->nnets, deleted);

    success = true;

 cleanup:
    for (i = 0; i < nAllNets; i++)
        VIR_FREE(names[i]);
    VIR_FREE(names);

    if (!success) {
        virshNetworkListFree(list);
        list = NULL;
    }

    return list;
}
Пример #3
0
static virshSecretListPtr
virshSecretListCollect(vshControl *ctl,
                       unsigned int flags)
{
    virshSecretListPtr list = vshMalloc(ctl, sizeof(*list));
    size_t i;
    int ret;
    virSecretPtr secret;
    bool success = false;
    size_t deleted = 0;
    int nsecrets = 0;
    char **uuids = NULL;
    virshControlPtr priv = ctl->privData;

    /* try the list with flags support (0.10.2 and later) */
    if ((ret = virConnectListAllSecrets(priv->conn,
                                        &list->secrets,
                                        flags)) >= 0) {
        list->nsecrets = ret;
        goto finished;
    }

    /* check if the command is actually supported */
    if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
        goto fallback;

    /* there was an error during the call */
    vshError(ctl, "%s", _("Failed to list node secrets"));
    goto cleanup;


 fallback:
    /* fall back to old method (0.10.1 and older) */
    vshResetLibvirtError();

    if (flags) {
        vshError(ctl, "%s", _("Filtering is not supported by this libvirt"));
        goto cleanup;
    }

    nsecrets = virConnectNumOfSecrets(priv->conn);
    if (nsecrets < 0) {
        vshError(ctl, "%s", _("Failed to count secrets"));
        goto cleanup;
    }

    if (nsecrets == 0)
        return list;

    uuids = vshMalloc(ctl, sizeof(char *) * nsecrets);

    nsecrets = virConnectListSecrets(priv->conn, uuids, nsecrets);
    if (nsecrets < 0) {
        vshError(ctl, "%s", _("Failed to list secrets"));
        goto cleanup;
    }

    list->secrets = vshMalloc(ctl, sizeof(virSecretPtr) * (nsecrets));
    list->nsecrets = 0;

    /* get the secrets */
    for (i = 0; i < nsecrets; i++) {
        if (!(secret = virSecretLookupByUUIDString(priv->conn, uuids[i])))
            continue;
        list->secrets[list->nsecrets++] = secret;
    }

    /* truncate secrets that weren't found */
    deleted = nsecrets - list->nsecrets;

 finished:
    /* sort the list */
    if (list->secrets && list->nsecrets)
        qsort(list->secrets, list->nsecrets,
              sizeof(*list->secrets), virshSecretSorter);

    /* truncate the list for not found secret objects */
    if (deleted)
        VIR_SHRINK_N(list->secrets, list->nsecrets, deleted);

    success = true;

 cleanup:
    if (nsecrets > 0) {
        for (i = 0; i < nsecrets; i++)
            VIR_FREE(uuids[i]);
        VIR_FREE(uuids);
    }

    if (!success) {
        virshSecretListFree(list);
        list = NULL;
    }

    return list;
}
Пример #4
0
static vshInterfaceListPtr
vshInterfaceListCollect(vshControl *ctl,
                        unsigned int flags)
{
    vshInterfaceListPtr list = vshMalloc(ctl, sizeof(*list));
    int i;
    int ret;
    char **activeNames = NULL;
    char **inactiveNames = NULL;
    virInterfacePtr iface;
    bool success = false;
    size_t deleted = 0;
    int nActiveIfaces = 0;
    int nInactiveIfaces = 0;
    int nAllIfaces = 0;

    /* try the list with flags support (0.10.2 and later) */
    if ((ret = virConnectListAllInterfaces(ctl->conn,
                                           &list->ifaces,
                                           flags)) >= 0) {
        list->nifaces = ret;
        goto finished;
    }

    /* check if the command is actually supported */
    if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
        goto fallback;

    /* there was an error during the first or second call */
    vshError(ctl, "%s", _("Failed to list interfaces"));
    goto cleanup;


fallback:
    /* fall back to old method (0.10.1 and older) */
    vshResetLibvirtError();

    if (flags & VIR_CONNECT_LIST_INTERFACES_ACTIVE) {
        nActiveIfaces = virConnectNumOfInterfaces(ctl->conn);
        if (nActiveIfaces < 0) {
            vshError(ctl, "%s", _("Failed to list active interfaces"));
            goto cleanup;
        }
        if (nActiveIfaces) {
            activeNames = vshMalloc(ctl, sizeof(char *) * nActiveIfaces);

            if ((nActiveIfaces = virConnectListInterfaces(ctl->conn, activeNames,
                                                          nActiveIfaces)) < 0) {
                vshError(ctl, "%s", _("Failed to list active interfaces"));
                goto cleanup;
            }
        }
    }

    if (flags & VIR_CONNECT_LIST_INTERFACES_INACTIVE) {
        nInactiveIfaces = virConnectNumOfDefinedInterfaces(ctl->conn);
        if (nInactiveIfaces < 0) {
            vshError(ctl, "%s", _("Failed to list inactive interfaces"));
            goto cleanup;
        }
        if (nInactiveIfaces) {
            inactiveNames = vshMalloc(ctl, sizeof(char *) * nInactiveIfaces);

            if ((nInactiveIfaces =
                     virConnectListDefinedInterfaces(ctl->conn, inactiveNames,
                                                     nInactiveIfaces)) < 0) {
                vshError(ctl, "%s", _("Failed to list inactive interfaces"));
                goto cleanup;
            }
        }
    }

    nAllIfaces = nActiveIfaces + nInactiveIfaces;
    if (nAllIfaces == 0) {
        VIR_FREE(activeNames);
        VIR_FREE(inactiveNames);
        return list;
    }

    list->ifaces = vshMalloc(ctl, sizeof(virInterfacePtr) * (nAllIfaces));
    list->nifaces = 0;

    /* get active interfaces */
    for (i = 0; i < nActiveIfaces; i++) {
        if (!(iface = virInterfaceLookupByName(ctl->conn, activeNames[i]))) {
            vshResetLibvirtError();
            continue;
        }
        list->ifaces[list->nifaces++] = iface;
    }

    /* get inactive interfaces */
    for (i = 0; i < nInactiveIfaces; i++) {
        if (!(iface = virInterfaceLookupByName(ctl->conn, inactiveNames[i]))) {
            vshResetLibvirtError();
            continue;
        }
        list->ifaces[list->nifaces++] = iface;
    }

    /* truncate interfaces that weren't found */
    deleted = nAllIfaces - list->nifaces;

finished:
    /* sort the list */
    if (list->ifaces && list->nifaces)
        qsort(list->ifaces, list->nifaces,
              sizeof(*list->ifaces), vshInterfaceSorter);

    /* truncate the list if filter simulation deleted entries */
    if (deleted)
        VIR_SHRINK_N(list->ifaces, list->nifaces, deleted);

    success = true;

cleanup:
    for (i = 0; i < nActiveIfaces; i++)
        VIR_FREE(activeNames[i]);

    for (i = 0; i < nInactiveIfaces; i++)
        VIR_FREE(inactiveNames[i]);

    VIR_FREE(activeNames);
    VIR_FREE(inactiveNames);

    if (!success) {
        vshInterfaceListFree(list);
        list = NULL;
    }

    return list;
}
Пример #5
0
int
virshRunConsole(vshControl *ctl,
                virDomainPtr dom,
                const char *dev_name,
                unsigned int flags)
{
    virConsolePtr con = NULL;
    virshControlPtr priv = ctl->privData;
    int ret = -1;

    struct sigaction old_sigquit;
    struct sigaction old_sigterm;
    struct sigaction old_sigint;
    struct sigaction old_sighup;
    struct sigaction old_sigpipe;
    struct sigaction sighandler = {.sa_handler = virConsoleHandleSignal,
                                   .sa_flags = SA_SIGINFO };

    sigemptyset(&sighandler.sa_mask);

    /* Put STDIN into raw mode so that stuff typed does not echo to the screen
     * (the TTY reads will result in it being echoed back already), and also
     * ensure Ctrl-C, etc is blocked, and misc other bits */
    if (vshTTYMakeRaw(ctl, true) < 0)
        goto resettty;

    if (!(con = virConsoleNew()))
        goto resettty;

    virObjectLock(con);

    /* Trap all common signals so that we can safely restore the original
     * terminal settings on STDIN before the process exits - people don't like
     * being left with a messed up terminal ! */
    sigaction(SIGQUIT, &sighandler, &old_sigquit);
    sigaction(SIGTERM, &sighandler, &old_sigterm);
    sigaction(SIGINT,  &sighandler, &old_sigint);
    sigaction(SIGHUP,  &sighandler, &old_sighup);
    sigaction(SIGPIPE, &sighandler, &old_sigpipe);

    con->escapeChar = virshGetEscapeChar(priv->escapeChar);
    con->st = virStreamNew(virDomainGetConnect(dom),
                           VIR_STREAM_NONBLOCK);
    if (!con->st)
        goto cleanup;

    if (virDomainOpenConsole(dom, dev_name, con->st, flags) < 0)
        goto cleanup;

    virObjectRef(con);
    if ((con->stdinWatch = virEventAddHandle(STDIN_FILENO,
                                             VIR_EVENT_HANDLE_READABLE,
                                             virConsoleEventOnStdin,
                                             con,
                                             virObjectFreeCallback)) < 0) {
        virObjectUnref(con);
        goto cleanup;
    }

    virObjectRef(con);
    if ((con->stdoutWatch = virEventAddHandle(STDOUT_FILENO,
                                              0,
                                              virConsoleEventOnStdout,
                                              con,
                                              virObjectFreeCallback)) < 0) {
        virObjectUnref(con);
        goto cleanup;
    }

    virObjectRef(con);
    if (virStreamEventAddCallback(con->st,
                                  VIR_STREAM_EVENT_READABLE,
                                  virConsoleEventOnStream,
                                  con,
                                  virObjectFreeCallback) < 0) {
        virObjectUnref(con);
        goto cleanup;
    }

    while (!con->quit) {
        if (virCondWait(&con->cond, &con->parent.lock) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unable to wait on console condition"));
            goto cleanup;
        }
    }

    if (con->error.code == VIR_ERR_OK)
        ret = 0;

 cleanup:
    virConsoleShutdown(con);

    if (ret < 0) {
        vshResetLibvirtError();
        virSetError(&con->error);
        vshSaveLibvirtHelperError();
    }

    virObjectUnlock(con);
    virObjectUnref(con);

    /* Restore original signal handlers */
    sigaction(SIGQUIT, &old_sigquit, NULL);
    sigaction(SIGTERM, &old_sigterm, NULL);
    sigaction(SIGINT,  &old_sigint,  NULL);
    sigaction(SIGHUP,  &old_sighup,  NULL);
    sigaction(SIGPIPE, &old_sigpipe, NULL);

 resettty:
    /* Put STDIN back into the (sane?) state we found
       it in before starting */
    vshTTYRestore(ctl);

    return ret;
}
Пример #6
0
static vshNodeDeviceListPtr
vshNodeDeviceListCollect(vshControl *ctl,
                         char **capnames,
                         int ncapnames,
                         unsigned int flags)
{
    vshNodeDeviceListPtr list = vshMalloc(ctl, sizeof(*list));
    int i;
    int ret;
    virNodeDevicePtr device;
    bool success = false;
    size_t deleted = 0;
    int ndevices = 0;
    char **names = NULL;

    /* try the list with flags support (0.10.2 and later) */
    if ((ret = virConnectListAllNodeDevices(ctl->conn,
                                            &list->devices,
                                            flags)) >= 0) {
        list->ndevices = ret;
        goto finished;
    }

    /* check if the command is actually supported */
    if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
        goto fallback;

    /* there was an error during the call */
    vshError(ctl, "%s", _("Failed to list node devices"));
    goto cleanup;


fallback:
    /* fall back to old method (0.10.1 and older) */
    vshResetLibvirtError();

    ndevices = virNodeNumOfDevices(ctl->conn, NULL, 0);
    if (ndevices < 0) {
        vshError(ctl, "%s", _("Failed to count node devices"));
        goto cleanup;
    }

    if (ndevices == 0)
        return list;

    names = vshMalloc(ctl, sizeof(char *) * ndevices);

    ndevices = virNodeListDevices(ctl->conn, NULL, names, ndevices, 0);
    if (ndevices < 0) {
        vshError(ctl, "%s", _("Failed to list node devices"));
        goto cleanup;
    }

    list->devices = vshMalloc(ctl, sizeof(virNodeDevicePtr) * (ndevices));
    list->ndevices = 0;

    /* get the node devices */
    for (i = 0; i < ndevices ; i++) {
        if (!(device = virNodeDeviceLookupByName(ctl->conn, names[i])))
            continue;
        list->devices[list->ndevices++] = device;
    }

    /* truncate domains that weren't found */
    deleted = ndevices - list->ndevices;

    if (!capnames)
        goto finished;

    /* filter the list if the list was acquired by fallback means */
    for (i = 0; i < list->ndevices; i++) {
        char **caps = NULL;
        int ncaps = 0;
        bool match = false;

        device = list->devices[i];

        if ((ncaps = virNodeDeviceNumOfCaps(device)) < 0) {
            vshError(ctl, "%s", _("Failed to get capability numbers "
                                  "of the device"));
            goto cleanup;
        }

        caps = vshMalloc(ctl, sizeof(char *) * ncaps);

        if ((ncaps = virNodeDeviceListCaps(device, caps, ncaps)) < 0) {
            vshError(ctl, "%s", _("Failed to get capability names of the device"));
            VIR_FREE(caps);
            goto cleanup;
        }

        /* Check if the device's capability matches with provied
         * capabilities.
         */
        int j, k;
        for (j = 0; j < ncaps; j++) {
            for (k = 0; k < ncapnames; k++) {
                if (STREQ(caps[j], capnames[k])) {
                    match = true;
                    break;
                }
            }
        }

        VIR_FREE(caps);

        if (!match)
            goto remove_entry;

        /* the device matched all filters, it may stay */
        continue;

remove_entry:
        /* the device has to be removed as it failed one of the filters */
        virNodeDeviceFree(list->devices[i]);
        list->devices[i] = NULL;
        deleted++;
    }

finished:
    /* sort the list */
    if (list->devices && list->ndevices)
        qsort(list->devices, list->ndevices,
              sizeof(*list->devices), vshNodeDeviceSorter);

    /* truncate the list if filter simulation deleted entries */
    if (deleted)
        VIR_SHRINK_N(list->devices, list->ndevices, deleted);

    success = true;

cleanup:
    for (i = 0; i < ndevices; i++)
        VIR_FREE(names[i]);
    VIR_FREE(names);

    if (!success) {
        vshNodeDeviceListFree(list);
        list = NULL;
    }

    return list;
}
Пример #7
0
virStorageVolPtr
vshCommandOptVolBy(vshControl *ctl, const vshCmd *cmd,
                   const char *optname,
                   const char *pooloptname,
                   const char **name, unsigned int flags)
{
    virStorageVolPtr vol = NULL;
    virStoragePoolPtr pool = NULL;
    const char *n = NULL, *p = NULL;
    virCheckFlags(VSH_BYUUID | VSH_BYNAME, NULL);

    if (vshCommandOptStringReq(ctl, cmd, optname, &n) < 0)
        return NULL;

    if (pooloptname != NULL &&
        vshCommandOptStringReq(ctl, cmd, pooloptname, &p) < 0)
        return NULL;

    if (p) {
        if (!(pool = vshCommandOptPoolBy(ctl, cmd, pooloptname, name, flags)))
            return NULL;

        if (virStoragePoolIsActive(pool) != 1) {
            vshError(ctl, _("pool '%s' is not active"), p);
            virStoragePoolFree(pool);
            return NULL;
        }
    }

    vshDebug(ctl, VSH_ERR_DEBUG, "%s: found option <%s>: %s\n",
             cmd->def->name, optname, n);

    if (name)
        *name = n;

    /* try it by name */
    if (pool && (flags & VSH_BYNAME)) {
        vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol name\n",
                 cmd->def->name, optname);
        vol = virStorageVolLookupByName(pool, n);
    }
    /* try it by key */
    if (!vol && (flags & VSH_BYUUID)) {
        vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol key\n",
                 cmd->def->name, optname);
        vol = virStorageVolLookupByKey(ctl->conn, n);
    }
    /* try it by path */
    if (!vol && (flags & VSH_BYUUID)) {
        vshDebug(ctl, VSH_ERR_DEBUG, "%s: <%s> trying as vol path\n",
                 cmd->def->name, optname);
        vol = virStorageVolLookupByPath(ctl->conn, n);
    }

    if (!vol) {
        if (pool || !pooloptname)
            vshError(ctl, _("failed to get vol '%s'"), n);
        else
            vshError(ctl, _("failed to get vol '%s', specifying --%s "
                            "might help"), n, pooloptname);
    }

    /* If the pool was specified, then make sure that the returned
     * volume is from the given pool */
    if (pool && vol) {
        virStoragePoolPtr volpool = NULL;

        if ((volpool = virStoragePoolLookupByVolume(vol))) {
            if (STRNEQ(virStoragePoolGetName(volpool),
                       virStoragePoolGetName(pool))) {
                vshResetLibvirtError();
                vshError(ctl,
                         _("Requested volume '%s' is not in pool '%s'"),
                         n, virStoragePoolGetName(pool));
                virStorageVolFree(vol);
                vol = NULL;
            }
            virStoragePoolFree(volpool);
        }
    }

    if (pool)
        virStoragePoolFree(pool);

    return vol;
}
Пример #8
0
static vshStorageVolListPtr
vshStorageVolListCollect(vshControl *ctl,
                         virStoragePoolPtr pool,
                         unsigned int flags)
{
    vshStorageVolListPtr list = vshMalloc(ctl, sizeof(*list));
    size_t i;
    char **names = NULL;
    virStorageVolPtr vol = NULL;
    bool success = false;
    size_t deleted = 0;
    int nvols = 0;
    int ret = -1;

    /* try the list with flags support (0.10.2 and later) */
    if ((ret = virStoragePoolListAllVolumes(pool,
                                            &list->vols,
                                            flags)) >= 0) {
        list->nvols = ret;
        goto finished;
    }

    /* check if the command is actually supported */
    if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
        goto fallback;

    /* there was an error during the call */
    vshError(ctl, "%s", _("Failed to list volumes"));
    goto cleanup;

 fallback:
    /* fall back to old method (0.10.1 and older) */
    vshResetLibvirtError();

    /* Determine the number of volumes in the pool */
    if ((nvols = virStoragePoolNumOfVolumes(pool)) < 0) {
        vshError(ctl, "%s", _("Failed to list storage volumes"));
        goto cleanup;
    }

    if (nvols == 0) {
        success = true;
        return list;
    }

    /* Retrieve the list of volume names in the pool */
    names = vshCalloc(ctl, nvols, sizeof(*names));
    if ((nvols = virStoragePoolListVolumes(pool, names, nvols)) < 0) {
        vshError(ctl, "%s", _("Failed to list storage volumes"));
        goto cleanup;
    }

    list->vols = vshMalloc(ctl, sizeof(virStorageVolPtr) * (nvols));
    list->nvols = 0;

    /* get the vols */
    for (i = 0; i < nvols; i++) {
        if (!(vol = virStorageVolLookupByName(pool, names[i])))
            continue;
        list->vols[list->nvols++] = vol;
    }

    /* truncate the list for not found vols */
    deleted = nvols - list->nvols;

 finished:
    /* sort the list */
    if (list->vols && list->nvols)
        qsort(list->vols, list->nvols, sizeof(*list->vols), vshStorageVolSorter);

    if (deleted)
        VIR_SHRINK_N(list->vols, list->nvols, deleted);

    success = true;

 cleanup:
    if (nvols > 0)
        for (i = 0; i < nvols; i++)
            VIR_FREE(names[i]);
    VIR_FREE(names);

    if (!success) {
        vshStorageVolListFree(list);
        list = NULL;
    }

    return list;
}