Index: include/libvirt/libvirt.h.in =================================================================== RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v retrieving revision 1.53 diff -u -r1.53 libvirt.h.in --- include/libvirt/libvirt.h.in 27 Aug 2008 20:05:58 -0000 1.53 +++ include/libvirt/libvirt.h.in 29 Aug 2008 12:29:24 -0000 @@ -75,6 +75,24 @@ VIR_DOMAIN_CRASHED = 6 /* the domain is crashed */ } virDomainState; +/* For virConnectListAllDomains. */ +#define VIR_DOMAIN_LIST_NOSTATE (1 << VIR_DOMAIN_NOSTATE) +#define VIR_DOMAIN_LIST_RUNNING (1 << VIR_DOMAIN_RUNNING) +#define VIR_DOMAIN_LIST_BLOCKED (1 << VIR_DOMAIN_BLOCKED) +#define VIR_DOMAIN_LIST_PAUSED (1 << VIR_DOMAIN_PAUSED) +#define VIR_DOMAIN_LIST_SHUTDOWN (1 << VIR_DOMAIN_SHUTDOWN) +#define VIR_DOMAIN_LIST_SHUTOFF (1 << VIR_DOMAIN_SHUTOFF) +#define VIR_DOMAIN_LIST_CRASHED (1 << VIR_DOMAIN_CRASHED) + +#define VIR_DOMAIN_LIST_ACTIVE (VIR_DOMAIN_LIST_NOSTATE | \ + VIR_DOMAIN_LIST_RUNNING | \ + VIR_DOMAIN_LIST_BLOCKED | \ + VIR_DOMAIN_LIST_PAUSED | \ + VIR_DOMAIN_LIST_SHUTDOWN | \ + VIR_DOMAIN_LIST_CRASHED) +#define VIR_DOMAIN_LIST_INACTIVE VIR_DOMAIN_LIST_SHUTOFF +#define VIR_DOMAIN_LIST_ALL (VIR_DOMAIN_LIST_ACTIVE | VIR_DOMAIN_LIST_INACTIVE) + /** * virDomainInfoPtr: * @@ -417,6 +435,14 @@ unsigned long long virNodeGetFreeMemory (virConnectPtr conn); /* + * New-style list-all-domains call. + */ +int virConnectListAllDomains(virConnectPtr conn, + virDomainPtr **domains, + virDomainInfo **infos, + int stateflags); + +/* * Gather list of running domains */ int virConnectListDomains (virConnectPtr conn, Index: qemud/remote.c =================================================================== RCS file: /data/cvs/libvirt/qemud/remote.c,v retrieving revision 1.39 diff -u -r1.39 remote.c --- qemud/remote.c 27 Aug 2008 20:05:59 -0000 1.39 +++ qemud/remote.c 29 Aug 2008 12:29:27 -0000 @@ -1904,6 +1904,62 @@ } static int +remoteDispatchListAllDomains (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_list_all_domains_args *args, + remote_list_all_domains_ret *ret) +{ + virDomainPtr *domains; + virDomainInfo *infos; + int i, nr; + int retcode = -2; + + CHECK_CONN(client); + + nr = virConnectListAllDomains (client->conn, &domains, &infos, + args->stateflags); + if (nr == -1) return -1; + + if (nr > REMOTE_DOMAIN_LIST_MAX || nr > REMOTE_DOMAIN_INFO_LIST_MAX) { + remoteDispatchSendError (client, req, VIR_ERR_RPC, + _("too many domains to return")); + goto done; + } + + if (VIR_ALLOC_N (ret->doms.doms_val, nr) == -1) { + remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL); + goto done; + } + if (VIR_ALLOC_N (ret->infos.infos_val, nr) == -1) { + remoteDispatchSendError(client, req, VIR_ERR_NO_MEMORY, NULL); + VIR_FREE (ret->doms.doms_val); + goto done; + } + + ret->doms.doms_len = nr; + ret->infos.infos_len = nr; + + for (i = 0; i < nr; ++i) { + make_nonnull_domain (&ret->doms.doms_val[i], domains[i]); + ret->infos.infos_val[i].state = infos[i].state; + ret->infos.infos_val[i].max_mem = infos[i].maxMem; + ret->infos.infos_val[i].memory = infos[i].memory; + ret->infos.infos_val[i].nr_virt_cpu = infos[i].nrVirtCpu; + ret->infos.infos_val[i].cpu_time = infos[i].cpuTime; + } + retcode = 0; + +done: + for (i = 0; i < nr; ++i) + virDomainFree (domains[i]); + free (domains); + free (infos); + + return retcode; +} + +static int remoteDispatchListDomains (struct qemud_server *server ATTRIBUTE_UNUSED, struct qemud_client *client, remote_message_header *req, Index: qemud/remote_protocol.c =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_protocol.c,v retrieving revision 1.17 diff -u -r1.17 remote_protocol.c --- qemud/remote_protocol.c 27 Aug 2008 20:05:59 -0000 1.17 +++ qemud/remote_protocol.c 29 Aug 2008 12:29:28 -0000 @@ -219,6 +219,23 @@ } bool_t +xdr_remote_domain_info (XDR *xdrs, remote_domain_info *objp) +{ + + if (!xdr_u_char (xdrs, &objp->state)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->max_mem)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->memory)) + return FALSE; + if (!xdr_u_short (xdrs, &objp->nr_virt_cpu)) + return FALSE; + if (!xdr_u_quad_t (xdrs, &objp->cpu_time)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_open_args (XDR *xdrs, remote_open_args *objp) { @@ -588,6 +605,30 @@ } bool_t +xdr_remote_list_all_domains_args (XDR *xdrs, remote_list_all_domains_args *objp) +{ + + if (!xdr_int (xdrs, &objp->stateflags)) + return FALSE; + return TRUE; +} + +bool_t +xdr_remote_list_all_domains_ret (XDR *xdrs, remote_list_all_domains_ret *objp) +{ + char **objp_cpp0 = (char **) (void *) &objp->doms.doms_val; + char **objp_cpp1 = (char **) (void *) &objp->infos.infos_val; + + if (!xdr_array (xdrs, objp_cpp0, (u_int *) &objp->doms.doms_len, REMOTE_DOMAIN_LIST_MAX, + sizeof (remote_nonnull_domain), (xdrproc_t) xdr_remote_nonnull_domain)) + return FALSE; + if (!xdr_array (xdrs, objp_cpp1, (u_int *) &objp->infos.infos_len, REMOTE_DOMAIN_INFO_LIST_MAX, + sizeof (remote_domain_info), (xdrproc_t) xdr_remote_domain_info)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_list_domains_args (XDR *xdrs, remote_list_domains_args *objp) { Index: qemud/remote_protocol.h =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_protocol.h,v retrieving revision 1.17 diff -u -r1.17 remote_protocol.h --- qemud/remote_protocol.h 27 Aug 2008 20:05:59 -0000 1.17 +++ qemud/remote_protocol.h 29 Aug 2008 12:29:29 -0000 @@ -23,6 +23,8 @@ typedef remote_nonnull_string *remote_string; #define REMOTE_DOMAIN_ID_LIST_MAX 16384 #define REMOTE_DOMAIN_NAME_LIST_MAX 1024 +#define REMOTE_DOMAIN_LIST_MAX 1024 +#define REMOTE_DOMAIN_INFO_LIST_MAX 1024 #define REMOTE_CPUMAP_MAX 256 #define REMOTE_VCPUINFO_MAX 2048 #define REMOTE_CPUMAPS_MAX 16384 @@ -122,6 +124,15 @@ }; typedef struct remote_sched_param remote_sched_param; +struct remote_domain_info { + u_char state; + u_quad_t max_mem; + u_quad_t memory; + u_short nr_virt_cpu; + u_quad_t cpu_time; +}; +typedef struct remote_domain_info remote_domain_info; + struct remote_open_args { remote_string name; int flags; @@ -299,6 +310,23 @@ }; typedef struct remote_domain_memory_peek_ret remote_domain_memory_peek_ret; +struct remote_list_all_domains_args { + int stateflags; +}; +typedef struct remote_list_all_domains_args remote_list_all_domains_args; + +struct remote_list_all_domains_ret { + struct { + u_int doms_len; + remote_nonnull_domain *doms_val; + } doms; + struct { + u_int infos_len; + remote_domain_info *infos_val; + } infos; +}; +typedef struct remote_list_all_domains_ret remote_list_all_domains_ret; + struct remote_list_domains_args { int maxids; }; @@ -1188,6 +1216,7 @@ REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, + REMOTE_PROC_LIST_ALL_DOMAINS = 105, }; typedef enum remote_procedure remote_procedure; @@ -1234,6 +1263,7 @@ extern bool_t xdr_remote_vcpu_info (XDR *, remote_vcpu_info*); extern bool_t xdr_remote_sched_param_value (XDR *, remote_sched_param_value*); extern bool_t xdr_remote_sched_param (XDR *, remote_sched_param*); +extern bool_t xdr_remote_domain_info (XDR *, remote_domain_info*); extern bool_t xdr_remote_open_args (XDR *, remote_open_args*); extern bool_t xdr_remote_supports_feature_args (XDR *, remote_supports_feature_args*); extern bool_t xdr_remote_supports_feature_ret (XDR *, remote_supports_feature_ret*); @@ -1260,6 +1290,8 @@ extern bool_t xdr_remote_domain_block_peek_ret (XDR *, remote_domain_block_peek_ret*); extern bool_t xdr_remote_domain_memory_peek_args (XDR *, remote_domain_memory_peek_args*); extern bool_t xdr_remote_domain_memory_peek_ret (XDR *, remote_domain_memory_peek_ret*); +extern bool_t xdr_remote_list_all_domains_args (XDR *, remote_list_all_domains_args*); +extern bool_t xdr_remote_list_all_domains_ret (XDR *, remote_list_all_domains_ret*); extern bool_t xdr_remote_list_domains_args (XDR *, remote_list_domains_args*); extern bool_t xdr_remote_list_domains_ret (XDR *, remote_list_domains_ret*); extern bool_t xdr_remote_num_of_domains_ret (XDR *, remote_num_of_domains_ret*); @@ -1415,6 +1447,7 @@ extern bool_t xdr_remote_vcpu_info (); extern bool_t xdr_remote_sched_param_value (); extern bool_t xdr_remote_sched_param (); +extern bool_t xdr_remote_domain_info (); extern bool_t xdr_remote_open_args (); extern bool_t xdr_remote_supports_feature_args (); extern bool_t xdr_remote_supports_feature_ret (); @@ -1441,6 +1474,8 @@ extern bool_t xdr_remote_domain_block_peek_ret (); extern bool_t xdr_remote_domain_memory_peek_args (); extern bool_t xdr_remote_domain_memory_peek_ret (); +extern bool_t xdr_remote_list_all_domains_args (); +extern bool_t xdr_remote_list_all_domains_ret (); extern bool_t xdr_remote_list_domains_args (); extern bool_t xdr_remote_list_domains_ret (); extern bool_t xdr_remote_num_of_domains_ret (); Index: qemud/remote_protocol.x =================================================================== RCS file: /data/cvs/libvirt/qemud/remote_protocol.x,v retrieving revision 1.17 diff -u -r1.17 remote_protocol.x --- qemud/remote_protocol.x 27 Aug 2008 20:05:59 -0000 1.17 +++ qemud/remote_protocol.x 29 Aug 2008 12:29:30 -0000 @@ -64,6 +64,12 @@ /* Upper limit on lists of domain names. */ const REMOTE_DOMAIN_NAME_LIST_MAX = 1024; +/* Upper limit on lists of domain structures. */ +const REMOTE_DOMAIN_LIST_MAX = 1024; + +/* Upper limit on lists of virDomainInfo structures. */ +const REMOTE_DOMAIN_INFO_LIST_MAX = 1024; + /* Upper limit on cpumap (bytes) passed to virDomainPinVcpu. */ const REMOTE_CPUMAP_MAX = 256; @@ -205,6 +211,15 @@ remote_sched_param_value value; }; +/* virDomainInfo on the wire */ +struct remote_domain_info { + unsigned char state; + unsigned hyper max_mem; + unsigned hyper memory; + unsigned short nr_virt_cpu; + unsigned hyper cpu_time; +}; + /*----- Calls. -----*/ /* For each call we may have a 'remote_CALL_args' and 'remote_CALL_ret' @@ -358,6 +373,15 @@ opaque buffer; }; +struct remote_list_all_domains_args { + int stateflags; +}; + +struct remote_list_all_domains_ret { + remote_nonnull_domain doms; + remote_domain_info infos; +}; + struct remote_list_domains_args { int maxids; }; @@ -455,6 +479,9 @@ }; struct remote_domain_get_info_ret { + /* remote_domain_info info; - but we have to maintain ABI compatibility + * so we cannot use the structure directly. + */ unsigned char state; unsigned hyper max_mem; unsigned hyper memory; @@ -1085,7 +1112,9 @@ REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, - REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104 + REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104, + + REMOTE_PROC_LIST_ALL_DOMAINS = 105 }; /* Custom RPC structure. */ Index: src/driver.h =================================================================== RCS file: /data/cvs/libvirt/src/driver.h,v retrieving revision 1.53 diff -u -r1.53 driver.h --- src/driver.h 27 Aug 2008 20:05:59 -0000 1.53 +++ src/driver.h 29 Aug 2008 12:29:30 -0000 @@ -97,6 +97,11 @@ typedef char * (*virDrvGetCapabilities) (virConnectPtr conn); typedef int + (*virDrvListAllDomains) (virConnectPtr conn, + virDomainPtr **domains, + virDomainInfo **infos, + int stateflags); +typedef int (*virDrvListDomains) (virConnectPtr conn, int *ids, int maxids); @@ -307,6 +312,7 @@ virDrvGetMaxVcpus getMaxVcpus; virDrvNodeGetInfo nodeGetInfo; virDrvGetCapabilities getCapabilities; + virDrvListAllDomains listAllDomains; virDrvListDomains listDomains; virDrvNumOfDomains numOfDomains; virDrvDomainCreateLinux domainCreateLinux; Index: src/libvirt.c =================================================================== RCS file: /data/cvs/libvirt/src/libvirt.c,v retrieving revision 1.154 diff -u -r1.154 libvirt.c --- src/libvirt.c 27 Aug 2008 20:05:59 -0000 1.154 +++ src/libvirt.c 29 Aug 2008 12:29:34 -0000 @@ -1145,6 +1145,180 @@ } /** + * virConnectListAllDomains: + * @conn: pointer to the hypervisor connection + * @domains: pointer to returned array of domain pointers + * @infos: pointer to returned array of virDomainInfo structures + * @stateflags: state of domains of interest + * + * This call returns the list of all domains, active or inactive, + * and their virDomainInfo structures. + * + * This call is usually more efficient than using the old method + * of calling virConnectListDomains and virConnectListDefinedDomains + * and then loading each domain and its info. This call is supported + * for all hypervisor types. (If the backend driver doesn't support it + * directly, then the call is emulated for you). + * + * @stateflags allows only the domains of interest to be + * returned. Common values are: + * VIR_DOMAIN_LIST_ACTIVE to return running domains. + * VIR_DOMAIN_LIST_INACTIVE to return defined but not running domains. + * VIR_DOMAIN_LIST_ALL to return all domains. + * And VIR_DOMAIN_LIST_NOSTATE (etc) to return domains in particular + * states. You may logically 'or' together several flags. + * + * Returns the number of domains in the @domains array, or -1 in + * case of error. + * + * If there was no error then the caller must free each domain + * with virDomainFree, free the array of @domains pointers, + * and free the array of @infos structures. + */ +int +virConnectListAllDomains(virConnectPtr conn, + virDomainPtr **domains, + virDomainInfo **infos, + int stateflags) +{ + DEBUG("conn=%p, domains=%p, stateflags=%d", conn, domains, stateflags); + + if (!VIR_IS_CONNECT (conn)) { + virLibConnError (NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return -1; + } + + /* Nothing can match an empty flag set. Error? Possibly. */ + if (stateflags == 0) { + *domains = NULL; + *infos = NULL; + return 0; + } + + if (domains == NULL || infos == NULL) { + virLibConnError (conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return -1; + } + + /* Supported by this driver? */ + if (conn->driver->listAllDomains) + return conn->driver->listAllDomains (conn, domains, infos, stateflags); + else { + /* Not supported, so emulate it. */ + int n_active, n_inactive; + int i, j, ret = -1; + int *ids = NULL; + char **names = NULL; + virDomainPtr tdom = NULL; + + n_active = + (stateflags & VIR_DOMAIN_LIST_ACTIVE) ? + virConnectNumOfDomains (conn) : + 0; + if (n_active == -1) return -1; + n_inactive = + (stateflags & VIR_DOMAIN_LIST_INACTIVE) ? + virConnectNumOfDefinedDomains (conn) : + 0; + if (n_inactive == -1) return -1; + + /* This over-allocates the return arrays, but that doesn't + * matter. + */ + if (VIR_ALLOC_N (*domains, n_active + n_inactive) == -1) { + virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__); + return -1; + } + if (VIR_ALLOC_N (*infos, n_active + n_inactive) == -1) { + VIR_FREE (*domains); + virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__); + return -1; + } + + /* 'j' is the next free position in the return array. */ + j = 0; + + if (n_active) { + if (VIR_ALLOC_N (ids, n_active) == -1) { + virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__); + goto done; + } + + n_active = virConnectListDomains (conn, ids, n_active); + if (n_active == -1) goto done; + + for (i = 0; i < n_active; ++i) { + /* Note: domains are allowed to disappear unexpectedly. */ + tdom = virDomainLookupByID (conn, ids[i]); + if (!tdom) continue; + + if (virDomainGetInfo (tdom, &((*infos)[j])) == -1) { + virDomainFree (tdom); + continue; + } + + if ((*infos)[j].state & stateflags) { + (*domains)[j++] = tdom; + tdom = NULL; + } else + virDomainFree (tdom); + } + } + + if (n_inactive) { + if (VIR_ALLOC_N (names, n_inactive) == -1) { + virLibConnError (conn, VIR_ERR_NO_MEMORY, __FUNCTION__); + goto done; + } + + n_inactive = virConnectListDefinedDomains (conn, names, n_inactive); + if (n_inactive == -1) goto done; + + for (i = 0; i < n_inactive; ++i) { + /* Note: domains are allowed to disappear unexpectedly. */ + tdom = virDomainLookupByName (conn, names[i]); + if (!tdom) continue; + + if (virDomainGetInfo (tdom, &((*infos)[j])) == -1) { + virDomainFree (tdom); + continue; + } + + /* By the logic above, if we are here at all then the + * caller must have requested inactive domains, so + * unconditionally add it to the list. Don't need to + * check the state flag. + */ + (*domains)[j++] = tdom; + tdom = NULL; + } + } + + /* Return the number of domains in the resulting list. */ + ret = j; + + done: + VIR_FREE (ids); + VIR_FREE (names); + + if (ret == -1) { + /* Error path: Free up any domains which we referenced, and + * also the domains & infos arrays. + */ + for (i = 0; i < j; ++i) + virDomainFree ((*domains)[i]); + VIR_FREE (*domains); + VIR_FREE (*infos); + + /* Free up the temporary domain. */ + if (tdom) + virDomainFree (tdom); + } + return ret; + } +} + +/** * virConnectListDomains: * @conn: pointer to the hypervisor connection * @ids: array to collect the list of IDs of active domains Index: src/libvirt_sym.version =================================================================== RCS file: /data/cvs/libvirt/src/libvirt_sym.version,v retrieving revision 1.44 diff -u -r1.44 libvirt_sym.version --- src/libvirt_sym.version 27 Aug 2008 20:05:59 -0000 1.44 +++ src/libvirt_sym.version 29 Aug 2008 12:29:34 -0000 @@ -12,6 +12,7 @@ virConnectGetHostname; virConnectGetURI; virDomainGetConnect; + virConnectListAllDomains; virConnectListDomains; virConnectNumOfDomains; virDomainCreate; Index: src/lxc_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/lxc_driver.c,v retrieving revision 1.25 diff -u -r1.25 lxc_driver.c --- src/lxc_driver.c 27 Aug 2008 11:42:52 -0000 1.25 +++ src/lxc_driver.c 29 Aug 2008 12:29:35 -0000 @@ -1127,6 +1127,7 @@ NULL, /* getMaxVcpus */ NULL, /* nodeGetInfo */ NULL, /* getCapabilities */ + NULL, /* listAllDomains */ lxcListDomains, /* listDomains */ lxcNumDomains, /* numOfDomains */ lxcDomainCreateAndStart, /* domainCreateLinux */ Index: src/openvz_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/openvz_driver.c,v retrieving revision 1.44 diff -u -r1.44 openvz_driver.c --- src/openvz_driver.c 27 Aug 2008 11:19:45 -0000 1.44 +++ src/openvz_driver.c 29 Aug 2008 12:29:35 -0000 @@ -930,6 +930,7 @@ openvzGetMaxVCPUs, /* getMaxVcpus */ openvzGetNodeInfo, /* nodeGetInfo */ NULL, /* getCapabilities */ + NULL, /* listAllDomains */ openvzListDomains, /* listDomains */ openvzNumDomains, /* numOfDomains */ openvzDomainCreateLinux, /* domainCreateLinux */ Index: src/qemu_driver.c =================================================================== RCS file: /data/cvs/libvirt/src/qemu_driver.c,v retrieving revision 1.113 diff -u -r1.113 qemu_driver.c --- src/qemu_driver.c 29 Aug 2008 07:11:15 -0000 1.113 +++ src/qemu_driver.c 29 Aug 2008 12:29:38 -0000 @@ -3872,6 +3872,7 @@ qemudGetMaxVCPUs, /* getMaxVcpus */ qemudGetNodeInfo, /* nodeGetInfo */ qemudGetCapabilities, /* getCapabilities */ + NULL, /* listAllDomains */ qemudListDomains, /* listDomains */ qemudNumDomains, /* numOfDomains */ qemudDomainCreate, /* domainCreateLinux */ Index: src/remote_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/remote_internal.c,v retrieving revision 1.83 diff -u -r1.83 remote_internal.c --- src/remote_internal.c 29 Aug 2008 07:11:15 -0000 1.83 +++ src/remote_internal.c 29 Aug 2008 12:29:41 -0000 @@ -1339,6 +1339,66 @@ return ret.freeMem; } +static int +remoteListAllDomains (virConnectPtr conn, + virDomainPtr **domains, + virDomainInfo **infos, + int stateflags) +{ + int i, nr; + remote_list_all_domains_args args; + remote_list_all_domains_ret ret; + GET_PRIVATE (conn, -1); + + args.stateflags = stateflags; + + memset (&ret, 0, sizeof ret); + if (call (conn, priv, 0, REMOTE_PROC_LIST_ALL_DOMAINS, + (xdrproc_t) xdr_remote_list_all_domains_args, (char *) &args, + (xdrproc_t) xdr_remote_list_all_domains_ret, (char *) &ret) == -1) + return -1; + + nr = ret.doms.doms_len; + if (ret.infos.infos_len != nr) { + errorf (conn, VIR_ERR_RPC, + _("length of domains and infos doesn't match: %d != %d"), + ret.infos.infos_len, ret.doms.doms_len); + xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret); + return -1; + } + if (nr > REMOTE_DOMAIN_LIST_MAX || nr > REMOTE_DOMAIN_INFO_LIST_MAX) { + errorf (conn, VIR_ERR_RPC, + _("length of domains list too long: %d > %d or > %d"), + nr, REMOTE_DOMAIN_LIST_MAX, REMOTE_DOMAIN_INFO_LIST_MAX); + xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret); + return -1; + } + + if (VIR_ALLOC_N (*domains, nr) == -1) { + errorf (conn, VIR_ERR_NO_MEMORY, _("out of memory")); + xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret); + return -1; + } + if (VIR_ALLOC_N (*infos, nr) == -1) { + xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret); + VIR_FREE (*domains); + errorf (conn, VIR_ERR_NO_MEMORY, _("out of memory")); + return -1; + } + + for (i = 0; i < nr; ++i) { + (*domains)[i] = get_nonnull_domain (conn, ret.doms.doms_val[i]); + (*infos)[i].state = ret.infos.infos_val[i].state; + (*infos)[i].maxMem = ret.infos.infos_val[i].max_mem; + (*infos)[i].memory = ret.infos.infos_val[i].memory; + (*infos)[i].nrVirtCpu = ret.infos.infos_val[i].nr_virt_cpu; + (*infos)[i].cpuTime = ret.infos.infos_val[i].cpu_time; + } + + xdr_free ((xdrproc_t) xdr_remote_list_domains_ret, (char *) &ret); + + return nr; +} static int remoteListDomains (virConnectPtr conn, int *ids, int maxids) @@ -4830,6 +4890,7 @@ .getMaxVcpus = remoteGetMaxVcpus, .nodeGetInfo = remoteNodeGetInfo, .getCapabilities = remoteGetCapabilities, + .listAllDomains = remoteListAllDomains, .listDomains = remoteListDomains, .numOfDomains = remoteNumOfDomains, .domainCreateLinux = remoteDomainCreateLinux, Index: src/test.c =================================================================== RCS file: /data/cvs/libvirt/src/test.c,v retrieving revision 1.84 diff -u -r1.84 test.c --- src/test.c 20 Aug 2008 20:48:36 -0000 1.84 +++ src/test.c 29 Aug 2008 12:29:42 -0000 @@ -1550,6 +1550,7 @@ testGetMaxVCPUs, /* getMaxVcpus */ testNodeGetInfo, /* nodeGetInfo */ testGetCapabilities, /* getCapabilities */ + NULL, /* listAllDomains */ testListDomains, /* listDomains */ testNumOfDomains, /* numOfDomains */ testDomainCreateLinux, /* domainCreateLinux */ Index: src/virsh.c =================================================================== RCS file: /data/cvs/libvirt/src/virsh.c,v retrieving revision 1.163 diff -u -r1.163 virsh.c --- src/virsh.c 27 Aug 2008 20:05:59 -0000 1.163 +++ src/virsh.c 29 Aug 2008 12:29:47 -0000 @@ -308,17 +308,6 @@ static char *_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line); #define vshStrdup(_ctl, _s) _vshStrdup(_ctl, _s, __FILE__, __LINE__) - -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 namesorter(const void *a, const void *b) { const char **sa = (const char**)a; const char **sb = (const char**)b; @@ -326,7 +315,6 @@ return strcasecmp(*sa, *sb); } - /* --------------- * Commands * --------------- @@ -559,104 +547,93 @@ }; +struct listedDom { + int id; /* INT_MAX if inactive. */ + char *name; /* strdup'd domain name. */ + const char *state_str; +}; + +static int +sortListedDoms (const void *a, const void *b) +{ + struct listedDom *sa = (struct listedDom *) a; + struct listedDom *sb = (struct listedDom *) b; + + if (sa->id == sb->id) { + return strcmp (sa->name, sb->name); + } else { + return sb->id - sa->id; + } +} + static int cmdList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED) { int inactive = vshCommandOptBool(cmd, "inactive"); int all = vshCommandOptBool(cmd, "all"); - int active = !inactive || all ? 1 : 0; - int *ids = NULL, maxid = 0, i; - char **names = NULL; - int maxname = 0; - inactive |= all; + virDomainPtr *domains; + virDomainInfo *infos; + int stateflags, i, nr, id; + struct listedDom *doms; + + if (all) + stateflags = VIR_DOMAIN_LIST_ALL; + else if (inactive) + stateflags = VIR_DOMAIN_LIST_INACTIVE; + else + stateflags = VIR_DOMAIN_LIST_ACTIVE; if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) return FALSE; - if (active) { - maxid = virConnectNumOfDomains(ctl->conn); - if (maxid < 0) { - vshError(ctl, FALSE, "%s", _("Failed to list active domains")); - return FALSE; - } - if (maxid) { - ids = vshMalloc(ctl, sizeof(int) * maxid); + nr = virConnectListAllDomains (ctl->conn, &domains, &infos, stateflags); + if (nr == -1) { + vshError(ctl, FALSE, "%s", _("Failed to list domains")); + return FALSE; + } - if ((maxid = virConnectListDomains(ctl->conn, &ids[0], maxid)) < 0) { - vshError(ctl, FALSE, "%s", _("Failed to list active domains")); - free(ids); - return FALSE; - } + /* Not quite so simple: The previous version showed domains + * sorted by ID, followed by inactive domains sorted by name. + * We must emulate this by pulling out the fields we need from + * the domains and infos structures and then sorting it. + */ + doms = vshMalloc (ctl, sizeof (struct listedDom) * nr); + for (i = 0; i < nr; ++i) { + id = virDomainGetID (domains[i]); + if (id == -1) id = INT_MAX; - qsort(&ids[0], maxid, sizeof(int), idsorter); - } + doms[i].id = id; + doms[i].name = vshStrdup (ctl, virDomainGetName (domains[i])); + doms[i].state_str = N_(vshDomainStateToString (infos[i].state)); + + virDomainFree (domains[i]); } - if (inactive) { - maxname = virConnectNumOfDefinedDomains(ctl->conn); - if (maxname < 0) { - vshError(ctl, FALSE, "%s", _("Failed to list inactive domains")); - free(ids); - return FALSE; - } - if (maxname) { - names = vshMalloc(ctl, sizeof(char *) * maxname); - if ((maxname = virConnectListDefinedDomains(ctl->conn, names, maxname)) < 0) { - vshError(ctl, FALSE, "%s", _("Failed to list inactive domains")); - free(ids); - free(names); - return FALSE; - } + free (domains); + free (infos); + + qsort (doms, nr, sizeof (struct listedDom), sortListedDoms); - qsort(&names[0], maxname, sizeof(char*), namesorter); - } - } vshPrintExtra(ctl, "%3s %-20s %s\n", _("Id"), _("Name"), _("State")); vshPrintExtra(ctl, "----------------------------------\n"); - for (i = 0; i < maxid; i++) { - virDomainInfo info; - virDomainPtr dom = virDomainLookupByID(ctl->conn, ids[i]); - const char *state; - - /* this kind of work with domains is not atomic operation */ - if (!dom) - continue; - - if (virDomainGetInfo(dom, &info) < 0) - state = _("no state"); + for (i = 0; i < nr; i++) { + if (doms[i].id != INT_MAX) + vshPrint(ctl, "%3d %-20s %s\n", + doms[i].id, + doms[i].name, + doms[i].state_str); else - state = N_(vshDomainStateToString(info.state)); + vshPrint(ctl, "%3s %-20s %s\n", + "-", + doms[i].name, + doms[i].state_str); - vshPrint(ctl, "%3d %-20s %s\n", - virDomainGetID(dom), - virDomainGetName(dom), - state); - virDomainFree(dom); + free (doms[i].name); } - for (i = 0; i < maxname; i++) { - virDomainInfo info; - virDomainPtr dom = virDomainLookupByName(ctl->conn, names[i]); - const char *state; - - /* this kind of work with domains is not atomic operation */ - if (!dom) { - free(names[i]); - continue; - } - - if (virDomainGetInfo(dom, &info) < 0) - state = _("no state"); - else - state = N_(vshDomainStateToString(info.state)); - vshPrint(ctl, "%3s %-20s %s\n", "-", names[i], state); + free (doms); - virDomainFree(dom); - free(names[i]); - } - free(ids); - free(names); return TRUE; }