Switch all the links to https
[ocaml-libvirt.git] / libvirt / libvirt_c_oneoffs.c
index 3bb572f..71ca78e 100644 (file)
@@ -1,6 +1,6 @@
 /* OCaml bindings for libvirt.
- * (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
- * http://libvirt.org/
+ * (C) Copyright 2007-2017 Richard W.M. Jones, Red Hat Inc.
+ * https://libvirt.org/
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 /* Please read libvirt/README file. */
 
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#endif
+
 /*----------------------------------------------------------------------*/
 
 CAMLprim value
@@ -32,7 +36,7 @@ ocaml_libvirt_get_version (value driverv, value unit)
 
   typeVer_ptr = driver ? &typeVer : NULL;
   NONBLOCKING (r = virGetVersion (&libVer, driver, typeVer_ptr));
-  CHECK_ERROR (r == -1, NULL, "virGetVersion");
+  CHECK_ERROR (r == -1, "virGetVersion");
 
   rv = caml_alloc_tuple (2);
   Store_field (rv, 0, Val_int (libVer));
@@ -53,7 +57,7 @@ ocaml_libvirt_connect_open (value namev, value unit)
   virConnectPtr conn;
 
   NONBLOCKING (conn = virConnectOpen (name));
-  CHECK_ERROR (!conn, NULL, "virConnectOpen");
+  CHECK_ERROR (!conn, "virConnectOpen");
 
   rv = Val_connect (conn);
 
@@ -69,8 +73,138 @@ ocaml_libvirt_connect_open_readonly (value namev, value unit)
   virConnectPtr conn;
 
   NONBLOCKING (conn = virConnectOpenReadOnly (name));
-  CHECK_ERROR (!conn, NULL, "virConnectOpen");
+  CHECK_ERROR (!conn, "virConnectOpen");
+
+  rv = Val_connect (conn);
+
+  CAMLreturn (rv);
+}
+
+/* Helper struct holding data needed for the helper C authentication
+ * callback (which will call the actual OCaml callback).
+ */
+struct ocaml_auth_callback_data {
+  value *fvp;                  /* The OCaml auth callback. */
+};
+
+static int
+_ocaml_auth_callback (virConnectCredentialPtr cred, unsigned int ncred, void *cbdata)
+{
+  CAMLparam0 ();
+  CAMLlocal4 (listv, elemv, rv, v);
+  struct ocaml_auth_callback_data *s = cbdata;
+  int i, len;
+
+  listv = Val_emptylist;
+  for (i = ncred - 1; i >= 0; --i) {
+    elemv = caml_alloc (2, 0);
+    Store_field (elemv, 0, Val_virconnectcredential (&cred[i]));
+    Store_field (elemv, 1, listv);
+    listv = elemv;
+  }
+
+  /* Call the auth callback. */
+  rv = caml_callback_exn (*s->fvp, listv);
+  if (Is_exception_result (rv)) {
+    /* The callback raised an exception, so return an error. */
+    CAMLreturnT (int, -1);
+  }
+
+  len = _list_length (rv);
+  if (len != (int) ncred) {
+    /* The callback did not return the same number of results as the
+     * credentials.
+     */
+    CAMLreturnT (int, -1);
+  }
+
+  for (i = 0; rv != Val_emptylist; rv = Field (rv, 1), ++i) {
+    virConnectCredentialPtr c = &cred[i];
+    elemv = Field (rv, 0);
+    if (elemv == Val_int (0)) {
+      c->result = NULL;
+      c->resultlen = 0;
+    } else {
+      v = Field (elemv, 0);
+      len = caml_string_length (v);
+      c->result = malloc (len + 1);
+      if (c->result == NULL)
+        CAMLreturnT (int, -1);
+      memcpy (c->result, String_val (v), len);
+      c->result[len] = '\0';
+      c->resultlen = len;
+    }
+  }
+
+  CAMLreturnT (int, 0);
+}
+
+static virConnectPtr
+_ocaml_libvirt_connect_open_auth_common (value namev, value authv, int flags)
+{
+  CAMLparam2 (namev, authv);
+  CAMLlocal2 (listv, fv);
+  virConnectPtr conn;
+  virConnectAuth auth;
+  struct ocaml_auth_callback_data data;
+  int i;
+  char *name = NULL;
+
+  /* Keep a copy of the 'namev' string, as its value could move around
+   * when calling other OCaml code that allocates memory.
+   */
+  if (namev != Val_int (0)) {  /* Some string */
+    name = strdup (String_val (Field (namev, 0)));
+    if (name == NULL)
+      caml_raise_out_of_memory ();
+  }
+
+  fv = Field (authv, 1);
+  data.fvp = &fv;
+
+  listv = Field (authv, 0);
+  auth.ncredtype = _list_length (listv);
+  auth.credtype = malloc (sizeof (int) * auth.ncredtype);
+  if (auth.credtype == NULL)
+    caml_raise_out_of_memory ();
+  for (i = 0; listv != Val_emptylist; listv = Field (listv, 1), ++i) {
+    auth.credtype[i] = Int_val (Field (listv, 0)) + 1;
+  }
+  auth.cb = &_ocaml_auth_callback;
+  auth.cbdata = &data;
+
+  /* Call virConnectOpenAuth directly, without using the NONBLOCKING
+   * macro, as this will indeed call ocaml_* APIs, and run OCaml code.
+   */
+  conn = virConnectOpenAuth (name, &auth, flags);
+  free (auth.credtype);
+  free (name);
+  CHECK_ERROR (!conn, "virConnectOpenAuth");
+
+  CAMLreturnT (virConnectPtr, conn);
+}
+
+CAMLprim value
+ocaml_libvirt_connect_open_auth (value namev, value authv)
+{
+  CAMLparam2 (namev, authv);
+  CAMLlocal1 (rv);
+  virConnectPtr conn;
 
+  conn = _ocaml_libvirt_connect_open_auth_common (namev, authv, 0);
+  rv = Val_connect (conn);
+
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_libvirt_connect_open_auth_readonly (value namev, value authv)
+{
+  CAMLparam2 (namev, authv);
+  CAMLlocal1 (rv);
+  virConnectPtr conn;
+
+  conn = _ocaml_libvirt_connect_open_auth_common (namev, authv, VIR_CONNECT_RO);
   rv = Val_connect (conn);
 
   CAMLreturn (rv);
@@ -85,7 +219,7 @@ ocaml_libvirt_connect_get_version (value connv)
   int r;
 
   NONBLOCKING (r = virConnectGetVersion (conn, &hvVer));
-  CHECK_ERROR (r == -1, conn, "virConnectGetVersion");
+  CHECK_ERROR (r == -1, "virConnectGetVersion");
 
   CAMLreturn (Val_int (hvVer));
 }
@@ -99,7 +233,7 @@ ocaml_libvirt_connect_get_max_vcpus (value connv, value typev)
   int r;
 
   NONBLOCKING (r = virConnectGetMaxVcpus (conn, type));
-  CHECK_ERROR (r == -1, conn, "virConnectGetMaxVcpus");
+  CHECK_ERROR (r == -1, "virConnectGetMaxVcpus");
 
   CAMLreturn (Val_int (r));
 }
@@ -114,7 +248,7 @@ ocaml_libvirt_connect_get_node_info (value connv)
   int r;
 
   NONBLOCKING (r = virNodeGetInfo (conn, &info));
-  CHECK_ERROR (r == -1, conn, "virNodeGetInfo");
+  CHECK_ERROR (r == -1, "virNodeGetInfo");
 
   rv = caml_alloc (8, 0);
   v = caml_copy_string (info.model); Store_field (rv, 0, v);
@@ -138,9 +272,9 @@ ocaml_libvirt_connect_node_get_free_memory (value connv)
   unsigned long long r;
 
   NONBLOCKING (r = virNodeGetFreeMemory (conn));
-  CHECK_ERROR (r == 0, conn, "virNodeGetFreeMemory");
+  CHECK_ERROR (r == 0, "virNodeGetFreeMemory");
 
-  rv = caml_copy_int64 ((int64) r);
+  rv = caml_copy_int64 ((int64_t) r);
   CAMLreturn (rv);
 }
 
@@ -154,16 +288,21 @@ ocaml_libvirt_connect_node_get_cells_free_memory (value connv,
   int start = Int_val (startv);
   int max = Int_val (maxv);
   int r, i;
-  unsigned long long freemems[max];
+  unsigned long long *freemems;
+
+  freemems = malloc(sizeof (*freemems) * max);
+  if (freemems == NULL)
+    caml_raise_out_of_memory ();
 
   NONBLOCKING (r = virNodeGetCellsFreeMemory (conn, freemems, start, max));
-  CHECK_ERROR (r == -1, conn, "virNodeGetCellsFreeMemory");
+  CHECK_ERROR_CLEANUP (r == -1, free (freemems), "virNodeGetCellsFreeMemory");
 
   rv = caml_alloc (r, 0);
   for (i = 0; i < r; ++i) {
-    iv = caml_copy_int64 ((int64) freemems[i]);
+    iv = caml_copy_int64 ((int64_t) freemems[i]);
     Store_field (rv, i, iv);
   }
+  free (freemems);
 
   CAMLreturn (rv);
 }
@@ -179,18 +318,112 @@ ocaml_libvirt_connect_set_keep_alive(value connv,
   int r;
 
   NONBLOCKING(r = virConnectSetKeepAlive(conn, interval, count));
-  CHECK_ERROR (r == -1, conn, "virConnectSetKeepAlive");
+  CHECK_ERROR (r == -1, "virConnectSetKeepAlive");
 
   CAMLreturn(Val_unit);
 }
 
+CAMLprim value
+ocaml_libvirt_connect_credtypes_from_auth_default (value unitv)
+{
+  CAMLparam1 (unitv);
+  CAMLlocal2 (listv, itemv);
+  int i;
+
+  listv = Val_emptylist;
+
+  if (virConnectAuthPtrDefault) {
+    for (i = virConnectAuthPtrDefault->ncredtype; i >= 0; --i) {
+      const int type = virConnectAuthPtrDefault->credtype[i];
+      itemv = caml_alloc (2, 0);
+      Store_field (itemv, 0, Val_int (type - 1));
+      Store_field (itemv, 1, listv);
+      listv = itemv;
+    }
+  }
+
+  CAMLreturn (listv);
+}
+
+CAMLprim value
+ocaml_libvirt_connect_call_auth_default_callback (value listv)
+{
+  CAMLparam1 (listv);
+  CAMLlocal5 (credv, retv, elemv, optv, v);
+  int i, len, ret;
+  const char *str;
+  virConnectCredentialPtr creds;
+
+  if (virConnectAuthPtrDefault == NULL
+      || virConnectAuthPtrDefault->cb == NULL)
+    CAMLreturn (Val_unit);
+
+  len = _list_length (listv);
+  creds = calloc (len, sizeof (*creds));
+  if (creds == NULL)
+    caml_raise_out_of_memory ();
+  for (i = 0; listv != Val_emptylist; listv = Field (listv, 1), ++i) {
+    virConnectCredentialPtr cred = &creds[i];
+    credv = Field (listv, 0);
+    cred->type = Int_val (Field (credv, 0)) + 1;
+    cred->prompt = strdup (String_val (Field (credv, 1)));
+    if (cred->prompt == NULL)
+      caml_raise_out_of_memory ();
+    str = Optstring_val (Field (credv, 2));
+    if (str) {
+      cred->challenge = strdup (str);
+      if (cred->challenge == NULL)
+        caml_raise_out_of_memory ();
+    }
+    str = Optstring_val (Field (credv, 3));
+    if (str) {
+      cred->defresult = strdup (str);
+      if (cred->defresult == NULL)
+        caml_raise_out_of_memory ();
+    }
+  }
+
+  ret = virConnectAuthPtrDefault->cb (creds, len,
+                                      virConnectAuthPtrDefault->cbdata);
+  if (ret >= 0) {
+    retv = Val_emptylist;
+    for (i = len - 1; i >= 0; --i) {
+      virConnectCredentialPtr cred = &creds[i];
+      elemv = caml_alloc (2, 0);
+      if (cred->result != NULL && cred->resultlen > 0) {
+        v = caml_alloc_string (cred->resultlen);
+        memcpy (String_val (v), cred->result, cred->resultlen);
+        optv = caml_alloc (1, 0);
+        Store_field (optv, 0, v);
+      } else
+        optv = Val_int (0);
+      Store_field (elemv, 0, optv);
+      Store_field (elemv, 1, retv);
+      retv = elemv;
+    }
+  }
+  for (i = 0; i < len; ++i) {
+    virConnectCredentialPtr cred = &creds[i];
+    /* Cast to char *, as the virConnectCredential structs we fill have
+     * const char * qualifiers.
+     */
+    free ((char *) cred->prompt);
+    free ((char *) cred->challenge);
+    free ((char *) cred->defresult);
+  }
+  free (creds);
+
+  if (ret < 0)
+    caml_failwith ("virConnectAuthPtrDefault callback failed");
+
+  CAMLreturn (retv);
+}
 
 CAMLprim value
 ocaml_libvirt_domain_get_id (value domv)
 {
   CAMLparam1 (domv);
   virDomainPtr dom = Domain_val (domv);
-  /*virConnectPtr conn = Connect_domv (domv);*/
   unsigned int r;
 
   NONBLOCKING (r = virDomainGetID (dom));
@@ -208,11 +441,10 @@ ocaml_libvirt_domain_get_max_memory (value domv)
   CAMLparam1 (domv);
   CAMLlocal1 (rv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   unsigned long r;
 
   NONBLOCKING (r = virDomainGetMaxMemory (dom));
-  CHECK_ERROR (r == 0 /* [sic] */, conn, "virDomainGetMaxMemory");
+  CHECK_ERROR (r == 0 /* [sic] */, "virDomainGetMaxMemory");
 
   rv = caml_copy_int64 (r);
   CAMLreturn (rv);
@@ -223,12 +455,11 @@ ocaml_libvirt_domain_set_max_memory (value domv, value memv)
 {
   CAMLparam2 (domv, memv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   unsigned long mem = Int64_val (memv);
   int r;
 
   NONBLOCKING (r = virDomainSetMaxMemory (dom, mem));
-  CHECK_ERROR (r == -1, conn, "virDomainSetMaxMemory");
+  CHECK_ERROR (r == -1, "virDomainSetMaxMemory");
 
   CAMLreturn (Val_unit);
 }
@@ -238,12 +469,11 @@ ocaml_libvirt_domain_set_memory (value domv, value memv)
 {
   CAMLparam2 (domv, memv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   unsigned long mem = Int64_val (memv);
   int r;
 
   NONBLOCKING (r = virDomainSetMemory (dom, mem));
-  CHECK_ERROR (r == -1, conn, "virDomainSetMemory");
+  CHECK_ERROR (r == -1, "virDomainSetMemory");
 
   CAMLreturn (Val_unit);
 }
@@ -254,12 +484,11 @@ ocaml_libvirt_domain_get_info (value domv)
   CAMLparam1 (domv);
   CAMLlocal2 (rv, v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   virDomainInfo info;
   int r;
 
   NONBLOCKING (r = virDomainGetInfo (dom, &info));
-  CHECK_ERROR (r == -1, conn, "virDomainGetInfo");
+  CHECK_ERROR (r == -1, "virDomainGetInfo");
 
   rv = caml_alloc (5, 0);
   Store_field (rv, 0, Val_int (info.state)); // These flags are compatible.
@@ -277,12 +506,11 @@ ocaml_libvirt_domain_get_scheduler_type (value domv)
   CAMLparam1 (domv);
   CAMLlocal2 (rv, strv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   char *r;
   int nparams;
 
   NONBLOCKING (r = virDomainGetSchedulerType (dom, &nparams));
-  CHECK_ERROR (!r, conn, "virDomainGetSchedulerType");
+  CHECK_ERROR (!r, "virDomainGetSchedulerType");
 
   rv = caml_alloc_tuple (2);
   strv = caml_copy_string (r); Store_field (rv, 0, strv);
@@ -297,13 +525,16 @@ ocaml_libvirt_domain_get_scheduler_parameters (value domv, value nparamsv)
   CAMLparam2 (domv, nparamsv);
   CAMLlocal4 (rv, v, v2, v3);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int nparams = Int_val (nparamsv);
-  virSchedParameter params[nparams];
+  virSchedParameterPtr params;
   int r, i;
 
+  params = malloc (sizeof (*params) * nparams);
+  if (params == NULL)
+    caml_raise_out_of_memory ();
+
   NONBLOCKING (r = virDomainGetSchedulerParameters (dom, params, &nparams));
-  CHECK_ERROR (r == -1, conn, "virDomainGetSchedulerParameters");
+  CHECK_ERROR_CLEANUP (r == -1, free (params), "virDomainGetSchedulerParameters");
 
   rv = caml_alloc (nparams, 0);
   for (i = 0; i < nparams; ++i) {
@@ -339,6 +570,7 @@ ocaml_libvirt_domain_get_scheduler_parameters (value domv, value nparamsv)
     }
     Store_field (v, 1, v2);
   }
+  free (params);
   CAMLreturn (rv);
 }
 
@@ -348,12 +580,15 @@ ocaml_libvirt_domain_set_scheduler_parameters (value domv, value paramsv)
   CAMLparam2 (domv, paramsv);
   CAMLlocal1 (v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int nparams = Wosize_val (paramsv);
-  virSchedParameter params[nparams];
+  virSchedParameterPtr params;
   int r, i;
   char *name;
 
+  params = malloc (sizeof (*params) * nparams);
+  if (params == NULL)
+    caml_raise_out_of_memory ();
+
   for (i = 0; i < nparams; ++i) {
     v = Field (paramsv, i);    /* Points to the two-element tuple. */
     name = String_val (Field (v, 0));
@@ -391,7 +626,8 @@ ocaml_libvirt_domain_set_scheduler_parameters (value domv, value paramsv)
   }
 
   NONBLOCKING (r = virDomainSetSchedulerParameters (dom, params, nparams));
-  CHECK_ERROR (r == -1, conn, "virDomainSetSchedulerParameters");
+  free (params);
+  CHECK_ERROR (r == -1, "virDomainSetSchedulerParameters");
 
   CAMLreturn (Val_unit);
 }
@@ -401,11 +637,10 @@ ocaml_libvirt_domain_set_vcpus (value domv, value nvcpusv)
 {
   CAMLparam2 (domv, nvcpusv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int r, nvcpus = Int_val (nvcpusv);
 
   NONBLOCKING (r = virDomainSetVcpus (dom, nvcpus));
-  CHECK_ERROR (r == -1, conn, "virDomainSetVcpus");
+  CHECK_ERROR (r == -1, "virDomainSetVcpus");
 
   CAMLreturn (Val_unit);
 }
@@ -415,14 +650,13 @@ ocaml_libvirt_domain_pin_vcpu (value domv, value vcpuv, value cpumapv)
 {
   CAMLparam3 (domv, vcpuv, cpumapv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int maplen = caml_string_length (cpumapv);
   unsigned char *cpumap = (unsigned char *) String_val (cpumapv);
   int vcpu = Int_val (vcpuv);
   int r;
 
   NONBLOCKING (r = virDomainPinVcpu (dom, vcpu, cpumap, maplen));
-  CHECK_ERROR (r == -1, conn, "virDomainPinVcpu");
+  CHECK_ERROR (r == -1, "virDomainPinVcpu");
 
   CAMLreturn (Val_unit);
 }
@@ -433,18 +667,23 @@ ocaml_libvirt_domain_get_vcpus (value domv, value maxinfov, value maplenv)
   CAMLparam3 (domv, maxinfov, maplenv);
   CAMLlocal5 (rv, infov, strv, v, v2);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int maxinfo = Int_val (maxinfov);
   int maplen = Int_val (maplenv);
-  virVcpuInfo info[maxinfo];
-  unsigned char cpumaps[maxinfo * maplen];
+  virVcpuInfoPtr info;
+  unsigned char *cpumaps;
   int r, i;
 
-  memset (info, 0, sizeof (virVcpuInfo) * maxinfo);
-  memset (cpumaps, 0, maxinfo * maplen);
+  info = calloc (maxinfo, sizeof (*info));
+  if (info == NULL)
+    caml_raise_out_of_memory ();
+  cpumaps = calloc (maxinfo * maplen, sizeof (*cpumaps));
+  if (cpumaps == NULL) {
+    free (info);
+    caml_raise_out_of_memory ();
+  }
 
   NONBLOCKING (r = virDomainGetVcpus (dom, info, maxinfo, cpumaps, maplen));
-  CHECK_ERROR (r == -1, conn, "virDomainPinVcpu");
+  CHECK_ERROR_CLEANUP (r == -1, free (info); free (cpumaps), "virDomainPinVcpu");
 
   /* Copy the virVcpuInfo structures. */
   infov = caml_alloc (maxinfo, 0);
@@ -466,6 +705,9 @@ ocaml_libvirt_domain_get_vcpus (value domv, value maxinfov, value maplenv)
   Store_field (rv, 1, infov);
   Store_field (rv, 2, strv);
 
+  free (info);
+  free (cpumaps);
+
   CAMLreturn (rv);
 }
 
@@ -476,18 +718,17 @@ ocaml_libvirt_domain_get_cpu_stats (value domv)
   CAMLlocal5 (cpustats, param_head, param_node, typed_param, typed_param_value);
   CAMLlocal1 (v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   virTypedParameterPtr params;
   int r, cpu, ncpus, nparams, i, j, pos;
   int nr_pcpus;
 
   /* get number of pcpus */
   NONBLOCKING (nr_pcpus = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0));
-  CHECK_ERROR (nr_pcpus < 0, conn, "virDomainGetCPUStats");
+  CHECK_ERROR (nr_pcpus < 0, "virDomainGetCPUStats");
 
   /* get percpu information */
   NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0));
-  CHECK_ERROR (nparams < 0, conn, "virDomainGetCPUStats");
+  CHECK_ERROR (nparams < 0, "virDomainGetCPUStats");
 
   if ((params = malloc(sizeof(*params) * nparams * 128)) == NULL)
     caml_failwith ("virDomainGetCPUStats: malloc");
@@ -498,7 +739,7 @@ ocaml_libvirt_domain_get_cpu_stats (value domv)
     ncpus = nr_pcpus - cpu > 128 ? 128 : nr_pcpus - cpu;
 
     NONBLOCKING (r = virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 0));
-    CHECK_ERROR (r < 0, conn, "virDomainGetCPUStats");
+    CHECK_ERROR (r < 0, "virDomainGetCPUStats");
 
     for (i = 0; i < ncpus; i++) {
       /* list of typed_param: single linked list of param_nodes */
@@ -572,6 +813,131 @@ ocaml_libvirt_domain_get_cpu_stats (value domv)
   CAMLreturn (cpustats);
 }
 
+value
+ocaml_libvirt_domain_get_all_domain_stats (value connv,
+                                           value statsv, value flagsv)
+{
+  CAMLparam3 (connv, statsv, flagsv);
+  CAMLlocal5 (rv, dsv, tpv, v, v1);
+  CAMLlocal1 (v2);
+  virConnectPtr conn = Connect_val (connv);
+  virDomainStatsRecordPtr *rstats;
+  unsigned int stats = 0, flags = 0;
+  int i, j, r;
+  unsigned char uuid[VIR_UUID_BUFLEN];
+
+  /* Get stats and flags. */
+  for (; statsv != Val_int (0); statsv = Field (statsv, 1)) {
+    v = Field (statsv, 0);
+    if (v == Val_int (0))
+      stats |= VIR_DOMAIN_STATS_STATE;
+    else if (v == Val_int (1))
+      stats |= VIR_DOMAIN_STATS_CPU_TOTAL;
+    else if (v == Val_int (2))
+      stats |= VIR_DOMAIN_STATS_BALLOON;
+    else if (v == Val_int (3))
+      stats |= VIR_DOMAIN_STATS_VCPU;
+    else if (v == Val_int (4))
+      stats |= VIR_DOMAIN_STATS_INTERFACE;
+    else if (v == Val_int (5))
+      stats |= VIR_DOMAIN_STATS_BLOCK;
+    else if (v == Val_int (6))
+      stats |= VIR_DOMAIN_STATS_PERF;
+  }
+  for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1)) {
+    v = Field (flagsv, 0);
+    if (v == Val_int (0))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE;
+    else if (v == Val_int (1))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE;
+    else if (v == Val_int (2))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_OTHER;
+    else if (v == Val_int (3))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_PAUSED;
+    else if (v == Val_int (4))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT;
+    else if (v == Val_int (5))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING;
+    else if (v == Val_int (6))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_SHUTOFF;
+    else if (v == Val_int (7))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT;
+    else if (v == Val_int (8))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_BACKING;
+    else if (v == Val_int (9))
+      flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS;
+  }
+
+  NONBLOCKING (r = virConnectGetAllDomainStats (conn, stats, &rstats, flags));
+  CHECK_ERROR (r == -1, "virConnectGetAllDomainStats");
+
+  rv = caml_alloc (r, 0);       /* domain_stats_record array. */
+  for (i = 0; i < r; ++i) {
+    dsv = caml_alloc (2, 0);    /* domain_stats_record */
+
+    /* Libvirt returns something superficially resembling a
+     * virDomainPtr, but it's not a real virDomainPtr object
+     * (eg. dom->id == -1, and its refcount is wrong).  The only thing
+     * we can safely get from it is the UUID.
+     */
+    v = caml_alloc_string (VIR_UUID_BUFLEN);
+    virDomainGetUUID (rstats[i]->dom, uuid);
+    memcpy (String_val (v), uuid, VIR_UUID_BUFLEN);
+    Store_field (dsv, 0, v);
+
+    tpv = caml_alloc (rstats[i]->nparams, 0); /* typed_param array */
+    for (j = 0; j < rstats[i]->nparams; ++j) {
+      v2 = caml_alloc (2, 0);   /* typed_param: field name, value */
+      Store_field (v2, 0, caml_copy_string (rstats[i]->params[j].field));
+
+      switch (rstats[i]->params[j].type) {
+      case VIR_TYPED_PARAM_INT:
+        v1 = caml_alloc (1, 0);
+        v = caml_copy_int32 (rstats[i]->params[j].value.i);
+        break;
+      case VIR_TYPED_PARAM_UINT:
+        v1 = caml_alloc (1, 1);
+        v = caml_copy_int32 (rstats[i]->params[j].value.ui);
+        break;
+      case VIR_TYPED_PARAM_LLONG:
+        v1 = caml_alloc (1, 2);
+        v = caml_copy_int64 (rstats[i]->params[j].value.l);
+        break;
+      case VIR_TYPED_PARAM_ULLONG:
+        v1 = caml_alloc (1, 3);
+        v = caml_copy_int64 (rstats[i]->params[j].value.ul);
+        break;
+      case VIR_TYPED_PARAM_DOUBLE:
+        v1 = caml_alloc (1, 4);
+        v = caml_copy_double (rstats[i]->params[j].value.d);
+        break;
+      case VIR_TYPED_PARAM_BOOLEAN:
+        v1 = caml_alloc (1, 5);
+        v = Val_bool (rstats[i]->params[j].value.b);
+        break;
+      case VIR_TYPED_PARAM_STRING:
+        v1 = caml_alloc (1, 6);
+        v = caml_copy_string (rstats[i]->params[j].value.s);
+        break;
+      default:
+        virDomainStatsRecordListFree (rstats);
+        caml_failwith ("virConnectGetAllDomainStats: "
+                       "unknown parameter type returned");
+      }
+      Store_field (v1, 0, v);
+
+      Store_field (v2, 1, v1);
+      Store_field (tpv, j, v2);
+    }
+
+    Store_field (dsv, 1, tpv);
+    Store_field (rv, i, dsv);
+  }
+
+  virDomainStatsRecordListFree (rstats);
+  CAMLreturn (rv);
+}
+
 CAMLprim value
 ocaml_libvirt_domain_migrate_native (value domv, value dconnv, value flagsv, value optdnamev, value opturiv, value optbandwidthv, value unitv)
 {
@@ -579,7 +945,6 @@ ocaml_libvirt_domain_migrate_native (value domv, value dconnv, value flagsv, val
   CAMLxparam2 (optbandwidthv, unitv);
   CAMLlocal2 (flagv, rv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   virConnectPtr dconn = Connect_val (dconnv);
   int flags = 0;
   const char *dname = Optstring_val (optdnamev);
@@ -601,7 +966,7 @@ ocaml_libvirt_domain_migrate_native (value domv, value dconnv, value flagsv, val
     bandwidth = Int_val (Field (optbandwidthv, 0));
 
   NONBLOCKING (r = virDomainMigrate (dom, dconn, flags, dname, uri, bandwidth));
-  CHECK_ERROR (!r, conn, "virDomainMigrate");
+  CHECK_ERROR (!r, "virDomainMigrate");
 
   rv = Val_domain (r, dconnv);
 
@@ -622,13 +987,12 @@ ocaml_libvirt_domain_block_stats (value domv, value pathv)
   CAMLparam2 (domv, pathv);
   CAMLlocal2 (rv,v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   char *path = String_val (pathv);
   struct _virDomainBlockStats stats;
   int r;
 
   NONBLOCKING (r = virDomainBlockStats (dom, path, &stats, sizeof stats));
-  CHECK_ERROR (r == -1, conn, "virDomainBlockStats");
+  CHECK_ERROR (r == -1, "virDomainBlockStats");
 
   rv = caml_alloc (5, 0);
   v = caml_copy_int64 (stats.rd_req); Store_field (rv, 0, v);
@@ -646,13 +1010,12 @@ ocaml_libvirt_domain_interface_stats (value domv, value pathv)
   CAMLparam2 (domv, pathv);
   CAMLlocal2 (rv,v);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   char *path = String_val (pathv);
   struct _virDomainInterfaceStats stats;
   int r;
 
   NONBLOCKING (r = virDomainInterfaceStats (dom, path, &stats, sizeof stats));
-  CHECK_ERROR (r == -1, conn, "virDomainInterfaceStats");
+  CHECK_ERROR (r == -1, "virDomainInterfaceStats");
 
   rv = caml_alloc (8, 0);
   v = caml_copy_int64 (stats.rx_bytes); Store_field (rv, 0, v);
@@ -673,7 +1036,6 @@ ocaml_libvirt_domain_block_peek_native (value domv, value pathv, value offsetv,
   CAMLparam5 (domv, pathv, offsetv, sizev, bufferv);
   CAMLxparam1 (boffv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   const char *path = String_val (pathv);
   unsigned long long offset = Int64_val (offsetv);
   size_t size = Int_val (sizev);
@@ -687,7 +1049,7 @@ ocaml_libvirt_domain_block_peek_native (value domv, value pathv, value offsetv,
 
   /* NB. not NONBLOCKING because buffer might move (XXX) */
   r = virDomainBlockPeek (dom, path, offset, size, buffer+boff, 0);
-  CHECK_ERROR (r == -1, conn, "virDomainBlockPeek");
+  CHECK_ERROR (r == -1, "virDomainBlockPeek");
 
   CAMLreturn (Val_unit);
 }
@@ -706,7 +1068,6 @@ ocaml_libvirt_domain_memory_peek_native (value domv, value flagsv, value offsetv
   CAMLxparam1 (boffv);
   CAMLlocal1 (flagv);
   virDomainPtr dom = Domain_val (domv);
-  virConnectPtr conn = Connect_domv (domv);
   int flags = 0;
   unsigned long long offset = Int64_val (offsetv);
   size_t size = Int_val (sizev);
@@ -728,7 +1089,7 @@ ocaml_libvirt_domain_memory_peek_native (value domv, value flagsv, value offsetv
 
   /* NB. not NONBLOCKING because buffer might move (XXX) */
   r = virDomainMemoryPeek (dom, offset, size, buffer+boff, flags);
-  CHECK_ERROR (r == -1, conn, "virDomainMemoryPeek");
+  CHECK_ERROR (r == -1, "virDomainMemoryPeek");
 
   CAMLreturn (Val_unit);
 }
@@ -740,6 +1101,37 @@ ocaml_libvirt_domain_memory_peek_bytecode (value *argv, int argn)
                                                   argv[3], argv[4], argv[5]);
 }
 
+CAMLprim value
+ocaml_libvirt_domain_get_xml_desc_flags (value domv, value flagsv)
+{
+  CAMLparam2 (domv, flagsv);
+  CAMLlocal2 (rv, flagv);
+  virDomainPtr dom = Domain_val (domv);
+  int flags = 0;
+  char *r;
+
+  /* Do flags. */
+  for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1))
+    {
+      flagv = Field (flagsv, 0);
+      if (flagv == Val_int (0))
+        flags |= VIR_DOMAIN_XML_SECURE;
+      else if (flagv == Val_int (1))
+        flags |= VIR_DOMAIN_XML_INACTIVE;
+      else if (flagv == Val_int (2))
+        flags |= VIR_DOMAIN_XML_UPDATE_CPU;
+      else if (flagv == Val_int (3))
+        flags |= VIR_DOMAIN_XML_MIGRATABLE;
+    }
+
+  NONBLOCKING (r = virDomainGetXMLDesc (dom, flags));
+  CHECK_ERROR (!r, "virDomainGetXMLDesc");
+
+  rv = caml_copy_string (r);
+  free (r);
+  CAMLreturn (rv);
+}
+
 /*----------------------------------------------------------------------*/
 
 /* Domain events */
@@ -1042,7 +1434,6 @@ CAMLprim value
 ocaml_libvirt_event_add_timeout (value connv, value ms, value callback_id)
 {
   CAMLparam3 (connv, ms, callback_id);
-  virConnectPtr conn = Connect_val (connv);
   void *opaque;
   virFreeCallback freecb = free;
   virEventTimeoutCallback cb = timeout_callback;
@@ -1055,7 +1446,7 @@ ocaml_libvirt_event_add_timeout (value connv, value ms, value callback_id)
     caml_failwith ("virEventAddTimeout: malloc");
   *((long*)opaque) = Int64_val(callback_id);
   NONBLOCKING(r = virEventAddTimeout(Int_val(ms), cb, opaque, freecb));
-  CHECK_ERROR(r == -1, conn, "virEventAddTimeout");
+  CHECK_ERROR(r == -1, "virEventAddTimeout");
 
   CAMLreturn(Val_int(r));
 }
@@ -1064,11 +1455,10 @@ CAMLprim value
 ocaml_libvirt_event_remove_timeout (value connv, value timer_id)
 {
   CAMLparam2 (connv, timer_id);
-  virConnectPtr conn = Connect_val (connv);
   int r;
 
   NONBLOCKING(r = virEventRemoveTimeout(Int_val(timer_id)));
-  CHECK_ERROR(r == -1, conn, "virEventRemoveTimeout");
+  CHECK_ERROR(r == -1, "virEventRemoveTimeout");
 
   CAMLreturn(Val_int(r));
 }
@@ -1146,7 +1536,7 @@ ocaml_libvirt_connect_domain_event_register_any(value connv, value domv, value c
     caml_failwith ("virConnectDomainEventRegisterAny: malloc");
   *((long*)opaque) = Int64_val(callback_id);
   NONBLOCKING(r = virConnectDomainEventRegisterAny(conn, dom, eventID, cb, opaque, freecb));
-  CHECK_ERROR(r == -1, conn, "virConnectDomainEventRegisterAny");
+  CHECK_ERROR(r == -1, "virConnectDomainEventRegisterAny");
 
   CAMLreturn(Val_int(r));
 }
@@ -1157,12 +1547,11 @@ ocaml_libvirt_storage_pool_get_info (value poolv)
   CAMLparam1 (poolv);
   CAMLlocal2 (rv, v);
   virStoragePoolPtr pool = Pool_val (poolv);
-  virConnectPtr conn = Connect_polv (poolv);
   virStoragePoolInfo info;
   int r;
 
   NONBLOCKING (r = virStoragePoolGetInfo (pool, &info));
-  CHECK_ERROR (r == -1, conn, "virStoragePoolGetInfo");
+  CHECK_ERROR (r == -1, "virStoragePoolGetInfo");
 
   rv = caml_alloc (4, 0);
   Store_field (rv, 0, Val_int (info.state));
@@ -1179,12 +1568,11 @@ ocaml_libvirt_storage_vol_get_info (value volv)
   CAMLparam1 (volv);
   CAMLlocal2 (rv, v);
   virStorageVolPtr vol = Volume_val (volv);
-  virConnectPtr conn = Connect_volv (volv);
   virStorageVolInfo info;
   int r;
 
   NONBLOCKING (r = virStorageVolGetInfo (vol, &info));
-  CHECK_ERROR (r == -1, conn, "virStorageVolGetInfo");
+  CHECK_ERROR (r == -1, "virStorageVolGetInfo");
 
   rv = caml_alloc (3, 0);
   Store_field (rv, 0, Val_int (info.type));
@@ -1194,6 +1582,58 @@ ocaml_libvirt_storage_vol_get_info (value volv)
   CAMLreturn (rv);
 }
 
+CAMLprim value
+ocaml_libvirt_secret_lookup_by_usage (value connv, value usagetypev, value usageidv)
+{
+  CAMLparam3 (connv, usagetypev, usageidv);
+  CAMLlocal1 (rv);
+  virConnectPtr conn = Connect_val (connv);
+  int usageType = Int_val (usagetypev);
+  const char *usageID = String_val (usageidv);
+  virSecretPtr r;
+
+  NONBLOCKING (r = virSecretLookupByUsage (conn, usageType, usageID));
+  CHECK_ERROR (!r, "virSecretLookupByUsage");
+
+  rv = Val_secret (r, connv);
+
+  CAMLreturn (rv);
+}
+
+CAMLprim value
+ocaml_libvirt_secret_set_value (value secv, value vv)
+{
+  CAMLparam2 (secv, vv);
+  virSecretPtr sec = Secret_val (secv);
+  const unsigned char *secval = (unsigned char *) String_val (vv);
+  const size_t size = caml_string_length (vv);
+  int r;
+
+  NONBLOCKING (r = virSecretSetValue (sec, secval, size, 0));
+  CHECK_ERROR (r == -1, "virSecretSetValue");
+
+  CAMLreturn (Val_unit);
+}
+
+CAMLprim value
+ocaml_libvirt_secret_get_value (value secv)
+{
+  CAMLparam1 (secv);
+  CAMLlocal1 (rv);
+  virSecretPtr sec = Secret_val (secv);
+  unsigned char *secval;
+  size_t size = 0;
+
+  NONBLOCKING (secval = virSecretGetValue (sec, &size, 0));
+  CHECK_ERROR (secval == NULL, "virSecretGetValue");
+
+  rv = caml_alloc_string (size);
+  memcpy (String_val (rv), secval, size);
+  free (secval);
+
+  CAMLreturn (rv);
+}
+
 /*----------------------------------------------------------------------*/
 
 CAMLprim value
@@ -1239,16 +1679,20 @@ ocaml_libvirt_virterror_reset_last_conn_error (value connv)
 
 /*----------------------------------------------------------------------*/
 
+static void
+ignore_errors (void *user_data, virErrorPtr error)
+{
+  /* do nothing */
+}
+
 /* Initialise the library. */
 CAMLprim value
 ocaml_libvirt_init (value unit)
 {
   CAMLparam1 (unit);
-  CAMLlocal1 (rv);
-  int r;
 
-  r = virInitialize ();
-  CHECK_ERROR (r == -1, NULL, "virInitialize");
+  virSetErrorFunc (NULL, ignore_errors);
+  virInitialize ();
 
   CAMLreturn (Val_unit);
 }