17412f5596fec9d2206b26aa6c59e30832f51eb6
[ocaml-libvirt.git] / libvirt / libvirt_c_oneoffs.c
1 /* OCaml bindings for libvirt.
2  * (C) Copyright 2007-2017 Richard W.M. Jones, Red Hat Inc.
3  * http://libvirt.org/
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
18  */
19
20 /* Please read libvirt/README file. */
21
22 /*----------------------------------------------------------------------*/
23
24 CAMLprim value
25 ocaml_libvirt_get_version (value driverv, value unit)
26 {
27   CAMLparam2 (driverv, unit);
28   CAMLlocal1 (rv);
29   const char *driver = Optstring_val (driverv);
30   unsigned long libVer, typeVer = 0, *typeVer_ptr;
31   int r;
32
33   typeVer_ptr = driver ? &typeVer : NULL;
34   NONBLOCKING (r = virGetVersion (&libVer, driver, typeVer_ptr));
35   CHECK_ERROR (r == -1, "virGetVersion");
36
37   rv = caml_alloc_tuple (2);
38   Store_field (rv, 0, Val_int (libVer));
39   Store_field (rv, 1, Val_int (typeVer));
40   CAMLreturn (rv);
41 }
42
43 /*----------------------------------------------------------------------*/
44
45 /* Connection object. */
46
47 CAMLprim value
48 ocaml_libvirt_connect_open (value namev, value unit)
49 {
50   CAMLparam2 (namev, unit);
51   CAMLlocal1 (rv);
52   const char *name = Optstring_val (namev);
53   virConnectPtr conn;
54
55   NONBLOCKING (conn = virConnectOpen (name));
56   CHECK_ERROR (!conn, "virConnectOpen");
57
58   rv = Val_connect (conn);
59
60   CAMLreturn (rv);
61 }
62
63 CAMLprim value
64 ocaml_libvirt_connect_open_readonly (value namev, value unit)
65 {
66   CAMLparam2 (namev, unit);
67   CAMLlocal1 (rv);
68   const char *name = Optstring_val (namev);
69   virConnectPtr conn;
70
71   NONBLOCKING (conn = virConnectOpenReadOnly (name));
72   CHECK_ERROR (!conn, "virConnectOpen");
73
74   rv = Val_connect (conn);
75
76   CAMLreturn (rv);
77 }
78
79 CAMLprim value
80 ocaml_libvirt_connect_get_version (value connv)
81 {
82   CAMLparam1 (connv);
83   virConnectPtr conn = Connect_val (connv);
84   unsigned long hvVer;
85   int r;
86
87   NONBLOCKING (r = virConnectGetVersion (conn, &hvVer));
88   CHECK_ERROR (r == -1, "virConnectGetVersion");
89
90   CAMLreturn (Val_int (hvVer));
91 }
92
93 CAMLprim value
94 ocaml_libvirt_connect_get_max_vcpus (value connv, value typev)
95 {
96   CAMLparam2 (connv, typev);
97   virConnectPtr conn = Connect_val (connv);
98   const char *type = Optstring_val (typev);
99   int r;
100
101   NONBLOCKING (r = virConnectGetMaxVcpus (conn, type));
102   CHECK_ERROR (r == -1, "virConnectGetMaxVcpus");
103
104   CAMLreturn (Val_int (r));
105 }
106
107 CAMLprim value
108 ocaml_libvirt_connect_get_node_info (value connv)
109 {
110   CAMLparam1 (connv);
111   CAMLlocal2 (rv, v);
112   virConnectPtr conn = Connect_val (connv);
113   virNodeInfo info;
114   int r;
115
116   NONBLOCKING (r = virNodeGetInfo (conn, &info));
117   CHECK_ERROR (r == -1, "virNodeGetInfo");
118
119   rv = caml_alloc (8, 0);
120   v = caml_copy_string (info.model); Store_field (rv, 0, v);
121   v = caml_copy_int64 (info.memory); Store_field (rv, 1, v);
122   Store_field (rv, 2, Val_int (info.cpus));
123   Store_field (rv, 3, Val_int (info.mhz));
124   Store_field (rv, 4, Val_int (info.nodes));
125   Store_field (rv, 5, Val_int (info.sockets));
126   Store_field (rv, 6, Val_int (info.cores));
127   Store_field (rv, 7, Val_int (info.threads));
128
129   CAMLreturn (rv);
130 }
131
132 CAMLprim value
133 ocaml_libvirt_connect_node_get_free_memory (value connv)
134 {
135   CAMLparam1 (connv);
136   CAMLlocal1 (rv);
137   virConnectPtr conn = Connect_val (connv);
138   unsigned long long r;
139
140   NONBLOCKING (r = virNodeGetFreeMemory (conn));
141   CHECK_ERROR (r == 0, "virNodeGetFreeMemory");
142
143   rv = caml_copy_int64 ((int64_t) r);
144   CAMLreturn (rv);
145 }
146
147 CAMLprim value
148 ocaml_libvirt_connect_node_get_cells_free_memory (value connv,
149                                                   value startv, value maxv)
150 {
151   CAMLparam3 (connv, startv, maxv);
152   CAMLlocal2 (rv, iv);
153   virConnectPtr conn = Connect_val (connv);
154   int start = Int_val (startv);
155   int max = Int_val (maxv);
156   int r, i;
157   unsigned long long freemems[max];
158
159   NONBLOCKING (r = virNodeGetCellsFreeMemory (conn, freemems, start, max));
160   CHECK_ERROR (r == -1, "virNodeGetCellsFreeMemory");
161
162   rv = caml_alloc (r, 0);
163   for (i = 0; i < r; ++i) {
164     iv = caml_copy_int64 ((int64_t) freemems[i]);
165     Store_field (rv, i, iv);
166   }
167
168   CAMLreturn (rv);
169 }
170
171 CAMLprim value
172 ocaml_libvirt_connect_set_keep_alive(value connv,
173                                      value intervalv, value countv)
174 {
175   CAMLparam3 (connv, intervalv, countv);
176   virConnectPtr conn = Connect_val(connv);
177   int interval = Int_val(intervalv);
178   unsigned int count = Int_val(countv);
179   int r;
180
181   NONBLOCKING(r = virConnectSetKeepAlive(conn, interval, count));
182   CHECK_ERROR (r == -1, "virConnectSetKeepAlive");
183
184   CAMLreturn(Val_unit);
185 }
186
187 CAMLprim value
188 ocaml_libvirt_domain_get_id (value domv)
189 {
190   CAMLparam1 (domv);
191   virDomainPtr dom = Domain_val (domv);
192   unsigned int r;
193
194   NONBLOCKING (r = virDomainGetID (dom));
195   /* In theory this could return -1 on error, but in practice
196    * libvirt never does this unless you call it with a corrupted
197    * or NULL dom object.  So ignore errors here.
198    */
199
200   CAMLreturn (Val_int ((int) r));
201 }
202
203 CAMLprim value
204 ocaml_libvirt_domain_get_max_memory (value domv)
205 {
206   CAMLparam1 (domv);
207   CAMLlocal1 (rv);
208   virDomainPtr dom = Domain_val (domv);
209   unsigned long r;
210
211   NONBLOCKING (r = virDomainGetMaxMemory (dom));
212   CHECK_ERROR (r == 0 /* [sic] */, "virDomainGetMaxMemory");
213
214   rv = caml_copy_int64 (r);
215   CAMLreturn (rv);
216 }
217
218 CAMLprim value
219 ocaml_libvirt_domain_set_max_memory (value domv, value memv)
220 {
221   CAMLparam2 (domv, memv);
222   virDomainPtr dom = Domain_val (domv);
223   unsigned long mem = Int64_val (memv);
224   int r;
225
226   NONBLOCKING (r = virDomainSetMaxMemory (dom, mem));
227   CHECK_ERROR (r == -1, "virDomainSetMaxMemory");
228
229   CAMLreturn (Val_unit);
230 }
231
232 CAMLprim value
233 ocaml_libvirt_domain_set_memory (value domv, value memv)
234 {
235   CAMLparam2 (domv, memv);
236   virDomainPtr dom = Domain_val (domv);
237   unsigned long mem = Int64_val (memv);
238   int r;
239
240   NONBLOCKING (r = virDomainSetMemory (dom, mem));
241   CHECK_ERROR (r == -1, "virDomainSetMemory");
242
243   CAMLreturn (Val_unit);
244 }
245
246 CAMLprim value
247 ocaml_libvirt_domain_get_info (value domv)
248 {
249   CAMLparam1 (domv);
250   CAMLlocal2 (rv, v);
251   virDomainPtr dom = Domain_val (domv);
252   virDomainInfo info;
253   int r;
254
255   NONBLOCKING (r = virDomainGetInfo (dom, &info));
256   CHECK_ERROR (r == -1, "virDomainGetInfo");
257
258   rv = caml_alloc (5, 0);
259   Store_field (rv, 0, Val_int (info.state)); // These flags are compatible.
260   v = caml_copy_int64 (info.maxMem); Store_field (rv, 1, v);
261   v = caml_copy_int64 (info.memory); Store_field (rv, 2, v);
262   Store_field (rv, 3, Val_int (info.nrVirtCpu));
263   v = caml_copy_int64 (info.cpuTime); Store_field (rv, 4, v);
264
265   CAMLreturn (rv);
266 }
267
268 CAMLprim value
269 ocaml_libvirt_domain_get_scheduler_type (value domv)
270 {
271   CAMLparam1 (domv);
272   CAMLlocal2 (rv, strv);
273   virDomainPtr dom = Domain_val (domv);
274   char *r;
275   int nparams;
276
277   NONBLOCKING (r = virDomainGetSchedulerType (dom, &nparams));
278   CHECK_ERROR (!r, "virDomainGetSchedulerType");
279
280   rv = caml_alloc_tuple (2);
281   strv = caml_copy_string (r); Store_field (rv, 0, strv);
282   free (r);
283   Store_field (rv, 1, nparams);
284   CAMLreturn (rv);
285 }
286
287 CAMLprim value
288 ocaml_libvirt_domain_get_scheduler_parameters (value domv, value nparamsv)
289 {
290   CAMLparam2 (domv, nparamsv);
291   CAMLlocal4 (rv, v, v2, v3);
292   virDomainPtr dom = Domain_val (domv);
293   int nparams = Int_val (nparamsv);
294   virSchedParameter params[nparams];
295   int r, i;
296
297   NONBLOCKING (r = virDomainGetSchedulerParameters (dom, params, &nparams));
298   CHECK_ERROR (r == -1, "virDomainGetSchedulerParameters");
299
300   rv = caml_alloc (nparams, 0);
301   for (i = 0; i < nparams; ++i) {
302     v = caml_alloc_tuple (2); Store_field (rv, i, v);
303     v2 = caml_copy_string (params[i].field); Store_field (v, 0, v2);
304     switch (params[i].type) {
305     case VIR_DOMAIN_SCHED_FIELD_INT:
306       v2 = caml_alloc (1, 0);
307       v3 = caml_copy_int32 (params[i].value.i); Store_field (v2, 0, v3);
308       break;
309     case VIR_DOMAIN_SCHED_FIELD_UINT:
310       v2 = caml_alloc (1, 1);
311       v3 = caml_copy_int32 (params[i].value.ui); Store_field (v2, 0, v3);
312       break;
313     case VIR_DOMAIN_SCHED_FIELD_LLONG:
314       v2 = caml_alloc (1, 2);
315       v3 = caml_copy_int64 (params[i].value.l); Store_field (v2, 0, v3);
316       break;
317     case VIR_DOMAIN_SCHED_FIELD_ULLONG:
318       v2 = caml_alloc (1, 3);
319       v3 = caml_copy_int64 (params[i].value.ul); Store_field (v2, 0, v3);
320       break;
321     case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
322       v2 = caml_alloc (1, 4);
323       v3 = caml_copy_double (params[i].value.d); Store_field (v2, 0, v3);
324       break;
325     case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
326       v2 = caml_alloc (1, 5);
327       Store_field (v2, 0, Val_int (params[i].value.b));
328       break;
329     default:
330       caml_failwith ((char *)__FUNCTION__);
331     }
332     Store_field (v, 1, v2);
333   }
334   CAMLreturn (rv);
335 }
336
337 CAMLprim value
338 ocaml_libvirt_domain_set_scheduler_parameters (value domv, value paramsv)
339 {
340   CAMLparam2 (domv, paramsv);
341   CAMLlocal1 (v);
342   virDomainPtr dom = Domain_val (domv);
343   int nparams = Wosize_val (paramsv);
344   virSchedParameter params[nparams];
345   int r, i;
346   char *name;
347
348   for (i = 0; i < nparams; ++i) {
349     v = Field (paramsv, i);     /* Points to the two-element tuple. */
350     name = String_val (Field (v, 0));
351     strncpy (params[i].field, name, VIR_DOMAIN_SCHED_FIELD_LENGTH);
352     params[i].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
353     v = Field (v, 1);           /* Points to the sched_param_value block. */
354     switch (Tag_val (v)) {
355     case 0:
356       params[i].type = VIR_DOMAIN_SCHED_FIELD_INT;
357       params[i].value.i = Int32_val (Field (v, 0));
358       break;
359     case 1:
360       params[i].type = VIR_DOMAIN_SCHED_FIELD_UINT;
361       params[i].value.ui = Int32_val (Field (v, 0));
362       break;
363     case 2:
364       params[i].type = VIR_DOMAIN_SCHED_FIELD_LLONG;
365       params[i].value.l = Int64_val (Field (v, 0));
366       break;
367     case 3:
368       params[i].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
369       params[i].value.ul = Int64_val (Field (v, 0));
370       break;
371     case 4:
372       params[i].type = VIR_DOMAIN_SCHED_FIELD_DOUBLE;
373       params[i].value.d = Double_val (Field (v, 0));
374       break;
375     case 5:
376       params[i].type = VIR_DOMAIN_SCHED_FIELD_BOOLEAN;
377       params[i].value.b = Int_val (Field (v, 0));
378       break;
379     default:
380       caml_failwith ((char *)__FUNCTION__);
381     }
382   }
383
384   NONBLOCKING (r = virDomainSetSchedulerParameters (dom, params, nparams));
385   CHECK_ERROR (r == -1, "virDomainSetSchedulerParameters");
386
387   CAMLreturn (Val_unit);
388 }
389
390 CAMLprim value
391 ocaml_libvirt_domain_set_vcpus (value domv, value nvcpusv)
392 {
393   CAMLparam2 (domv, nvcpusv);
394   virDomainPtr dom = Domain_val (domv);
395   int r, nvcpus = Int_val (nvcpusv);
396
397   NONBLOCKING (r = virDomainSetVcpus (dom, nvcpus));
398   CHECK_ERROR (r == -1, "virDomainSetVcpus");
399
400   CAMLreturn (Val_unit);
401 }
402
403 CAMLprim value
404 ocaml_libvirt_domain_pin_vcpu (value domv, value vcpuv, value cpumapv)
405 {
406   CAMLparam3 (domv, vcpuv, cpumapv);
407   virDomainPtr dom = Domain_val (domv);
408   int maplen = caml_string_length (cpumapv);
409   unsigned char *cpumap = (unsigned char *) String_val (cpumapv);
410   int vcpu = Int_val (vcpuv);
411   int r;
412
413   NONBLOCKING (r = virDomainPinVcpu (dom, vcpu, cpumap, maplen));
414   CHECK_ERROR (r == -1, "virDomainPinVcpu");
415
416   CAMLreturn (Val_unit);
417 }
418
419 CAMLprim value
420 ocaml_libvirt_domain_get_vcpus (value domv, value maxinfov, value maplenv)
421 {
422   CAMLparam3 (domv, maxinfov, maplenv);
423   CAMLlocal5 (rv, infov, strv, v, v2);
424   virDomainPtr dom = Domain_val (domv);
425   int maxinfo = Int_val (maxinfov);
426   int maplen = Int_val (maplenv);
427   virVcpuInfo info[maxinfo];
428   unsigned char cpumaps[maxinfo * maplen];
429   int r, i;
430
431   memset (info, 0, sizeof (virVcpuInfo) * maxinfo);
432   memset (cpumaps, 0, maxinfo * maplen);
433
434   NONBLOCKING (r = virDomainGetVcpus (dom, info, maxinfo, cpumaps, maplen));
435   CHECK_ERROR (r == -1, "virDomainPinVcpu");
436
437   /* Copy the virVcpuInfo structures. */
438   infov = caml_alloc (maxinfo, 0);
439   for (i = 0; i < maxinfo; ++i) {
440     v2 = caml_alloc (4, 0); Store_field (infov, i, v2);
441     Store_field (v2, 0, Val_int (info[i].number));
442     Store_field (v2, 1, Val_int (info[i].state));
443     v = caml_copy_int64 (info[i].cpuTime); Store_field (v2, 2, v);
444     Store_field (v2, 3, Val_int (info[i].cpu));
445   }
446
447   /* Copy the bitmap. */
448   strv = caml_alloc_string (maxinfo * maplen);
449   memcpy (String_val (strv), cpumaps, maxinfo * maplen);
450
451   /* Allocate the tuple and return it. */
452   rv = caml_alloc_tuple (3);
453   Store_field (rv, 0, Val_int (r)); /* number of CPUs. */
454   Store_field (rv, 1, infov);
455   Store_field (rv, 2, strv);
456
457   CAMLreturn (rv);
458 }
459
460 CAMLprim value
461 ocaml_libvirt_domain_get_cpu_stats (value domv)
462 {
463   CAMLparam1 (domv);
464   CAMLlocal5 (cpustats, param_head, param_node, typed_param, typed_param_value);
465   CAMLlocal1 (v);
466   virDomainPtr dom = Domain_val (domv);
467   virTypedParameterPtr params;
468   int r, cpu, ncpus, nparams, i, j, pos;
469   int nr_pcpus;
470
471   /* get number of pcpus */
472   NONBLOCKING (nr_pcpus = virDomainGetCPUStats(dom, NULL, 0, 0, 0, 0));
473   CHECK_ERROR (nr_pcpus < 0, "virDomainGetCPUStats");
474
475   /* get percpu information */
476   NONBLOCKING (nparams = virDomainGetCPUStats(dom, NULL, 0, 0, 1, 0));
477   CHECK_ERROR (nparams < 0, "virDomainGetCPUStats");
478
479   if ((params = malloc(sizeof(*params) * nparams * 128)) == NULL)
480     caml_failwith ("virDomainGetCPUStats: malloc");
481
482   cpustats = caml_alloc (nr_pcpus, 0); /* cpustats: array of params(list of typed_param) */
483   cpu = 0;
484   while (cpu < nr_pcpus) {
485     ncpus = nr_pcpus - cpu > 128 ? 128 : nr_pcpus - cpu;
486
487     NONBLOCKING (r = virDomainGetCPUStats(dom, params, nparams, cpu, ncpus, 0));
488     CHECK_ERROR (r < 0, "virDomainGetCPUStats");
489
490     for (i = 0; i < ncpus; i++) {
491       /* list of typed_param: single linked list of param_nodes */
492       param_head = Val_emptylist; /* param_head: the head param_node of list of typed_param */
493
494       if (params[i * nparams].type == 0) {
495         Store_field(cpustats, cpu + i, param_head);
496         continue;
497       }
498
499       for (j = r - 1; j >= 0; j--) {
500         pos = i * nparams + j;
501           if (params[pos].type == 0)
502             continue;
503
504         param_node = caml_alloc(2, 0); /* param_node: typed_param, next param_node */
505         Store_field(param_node, 1, param_head);
506         param_head = param_node;
507
508         typed_param = caml_alloc(2, 0); /* typed_param: field name(string), typed_param_value */
509         Store_field(param_node, 0, typed_param);
510         Store_field(typed_param, 0, caml_copy_string(params[pos].field));
511
512         /* typed_param_value: value with the corresponding type tag */
513         switch(params[pos].type) {
514         case VIR_TYPED_PARAM_INT:
515           typed_param_value = caml_alloc (1, 0);
516           v = caml_copy_int32 (params[pos].value.i);
517           break;
518         case VIR_TYPED_PARAM_UINT:
519           typed_param_value = caml_alloc (1, 1);
520           v = caml_copy_int32 (params[pos].value.ui);
521           break;
522         case VIR_TYPED_PARAM_LLONG:
523           typed_param_value = caml_alloc (1, 2);
524           v = caml_copy_int64 (params[pos].value.l);
525           break;
526         case VIR_TYPED_PARAM_ULLONG:
527           typed_param_value = caml_alloc (1, 3);
528           v = caml_copy_int64 (params[pos].value.ul);
529           break;
530         case VIR_TYPED_PARAM_DOUBLE:
531           typed_param_value = caml_alloc (1, 4);
532           v = caml_copy_double (params[pos].value.d);
533           break;
534         case VIR_TYPED_PARAM_BOOLEAN:
535           typed_param_value = caml_alloc (1, 5);
536           v = Val_bool (params[pos].value.b);
537           break;
538         case VIR_TYPED_PARAM_STRING:
539           typed_param_value = caml_alloc (1, 6);
540           v = caml_copy_string (params[pos].value.s);
541           free (params[pos].value.s);
542           break;
543         default:
544             /* XXX Memory leak on this path, if there are more
545              * VIR_TYPED_PARAM_STRING past this point in the array.
546              */
547           free (params);
548           caml_failwith ("virDomainGetCPUStats: "
549                          "unknown parameter type returned");
550         }
551         Store_field (typed_param_value, 0, v);
552         Store_field (typed_param, 1, typed_param_value);
553       }
554       Store_field (cpustats, cpu + i, param_head);
555     }
556     cpu += ncpus;
557   }
558   free(params);
559   CAMLreturn (cpustats);
560 }
561
562 value
563 ocaml_libvirt_domain_get_all_domain_stats (value connv,
564                                            value statsv, value flagsv)
565 {
566   CAMLparam3 (connv, statsv, flagsv);
567   CAMLlocal5 (rv, dsv, tpv, v, v1);
568   CAMLlocal1 (v2);
569   virConnectPtr conn = Connect_val (connv);
570   virDomainStatsRecordPtr *rstats;
571   unsigned int stats = 0, flags = 0;
572   int i, j, r;
573
574   /* Get stats and flags. */
575   for (; statsv != Val_int (0); statsv = Field (statsv, 1)) {
576     v = Field (statsv, 0);
577     if (v == Val_int (0))
578       stats |= VIR_DOMAIN_STATS_STATE;
579     else if (v == Val_int (1))
580       stats |= VIR_DOMAIN_STATS_CPU_TOTAL;
581     else if (v == Val_int (2))
582       stats |= VIR_DOMAIN_STATS_BALLOON;
583     else if (v == Val_int (3))
584       stats |= VIR_DOMAIN_STATS_VCPU;
585     else if (v == Val_int (4))
586       stats |= VIR_DOMAIN_STATS_INTERFACE;
587     else if (v == Val_int (5))
588       stats |= VIR_DOMAIN_STATS_BLOCK;
589     else if (v == Val_int (6))
590       stats |= VIR_DOMAIN_STATS_PERF;
591   }
592   for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1)) {
593     v = Field (flagsv, 0);
594     if (v == Val_int (0))
595       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE;
596     else if (v == Val_int (1))
597       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE;
598     else if (v == Val_int (2))
599       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_OTHER;
600     else if (v == Val_int (3))
601       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_PAUSED;
602     else if (v == Val_int (4))
603       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT;
604     else if (v == Val_int (5))
605       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING;
606     else if (v == Val_int (6))
607       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_SHUTOFF;
608     else if (v == Val_int (7))
609       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT;
610     else if (v == Val_int (8))
611       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_BACKING;
612     else if (v == Val_int (9))
613       flags |= VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS;
614   }
615
616   NONBLOCKING (r = virConnectGetAllDomainStats (conn, stats, &rstats, flags));
617   CHECK_ERROR (r == -1, "virConnectGetAllDomainStats");
618
619   rv = caml_alloc (r, 0);       /* domain_stats_record array. */
620   for (i = 0; i < r; ++i) {
621     dsv = caml_alloc (2, 0);    /* domain_stats_record */
622     virDomainRef (rstats[i]->dom);
623     Store_field (dsv, 0, Val_domain (rstats[i]->dom, connv));
624
625     tpv = caml_alloc (rstats[i]->nparams, 0); /* typed_param array */
626     for (j = 0; j < rstats[i]->nparams; ++j) {
627       v2 = caml_alloc (2, 0);   /* typed_param: field name, value */
628       Store_field (v2, 0, caml_copy_string (rstats[i]->params[j].field));
629
630       switch (rstats[i]->params[j].type) {
631       case VIR_TYPED_PARAM_INT:
632         v1 = caml_alloc (1, 0);
633         v = caml_copy_int32 (rstats[i]->params[j].value.i);
634         break;
635       case VIR_TYPED_PARAM_UINT:
636         v1 = caml_alloc (1, 1);
637         v = caml_copy_int32 (rstats[i]->params[j].value.ui);
638         break;
639       case VIR_TYPED_PARAM_LLONG:
640         v1 = caml_alloc (1, 2);
641         v = caml_copy_int64 (rstats[i]->params[j].value.l);
642         break;
643       case VIR_TYPED_PARAM_ULLONG:
644         v1 = caml_alloc (1, 3);
645         v = caml_copy_int64 (rstats[i]->params[j].value.ul);
646         break;
647       case VIR_TYPED_PARAM_DOUBLE:
648         v1 = caml_alloc (1, 4);
649         v = caml_copy_double (rstats[i]->params[j].value.d);
650         break;
651       case VIR_TYPED_PARAM_BOOLEAN:
652         v1 = caml_alloc (1, 5);
653         v = Val_bool (rstats[i]->params[j].value.b);
654         break;
655       case VIR_TYPED_PARAM_STRING:
656         v1 = caml_alloc (1, 6);
657         v = caml_copy_string (rstats[i]->params[j].value.s);
658         break;
659       default:
660         virDomainStatsRecordListFree (rstats);
661         caml_failwith ("virConnectGetAllDomainStats: "
662                        "unknown parameter type returned");
663       }
664       Store_field (v1, 0, v);
665
666       Store_field (v2, 1, v1);
667       Store_field (tpv, j, v2);
668     }
669
670     Store_field (dsv, 1, tpv);
671     Store_field (rv, i, dsv);
672   }
673
674   virDomainStatsRecordListFree (rstats);
675   CAMLreturn (rv);
676 }
677
678 CAMLprim value
679 ocaml_libvirt_domain_migrate_native (value domv, value dconnv, value flagsv, value optdnamev, value opturiv, value optbandwidthv, value unitv)
680 {
681   CAMLparam5 (domv, dconnv, flagsv, optdnamev, opturiv);
682   CAMLxparam2 (optbandwidthv, unitv);
683   CAMLlocal2 (flagv, rv);
684   virDomainPtr dom = Domain_val (domv);
685   virConnectPtr dconn = Connect_val (dconnv);
686   int flags = 0;
687   const char *dname = Optstring_val (optdnamev);
688   const char *uri = Optstring_val (opturiv);
689   unsigned long bandwidth;
690   virDomainPtr r;
691
692   /* Iterate over the list of flags. */
693   for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1))
694     {
695       flagv = Field (flagsv, 0);
696       if (flagv == Val_int (0))
697         flags |= VIR_MIGRATE_LIVE;
698     }
699
700   if (optbandwidthv == Val_int (0)) /* None */
701     bandwidth = 0;
702   else                          /* Some bandwidth */
703     bandwidth = Int_val (Field (optbandwidthv, 0));
704
705   NONBLOCKING (r = virDomainMigrate (dom, dconn, flags, dname, uri, bandwidth));
706   CHECK_ERROR (!r, "virDomainMigrate");
707
708   rv = Val_domain (r, dconnv);
709
710   CAMLreturn (rv);
711 }
712
713 CAMLprim value
714 ocaml_libvirt_domain_migrate_bytecode (value *argv, int argn)
715 {
716   return ocaml_libvirt_domain_migrate_native (argv[0], argv[1], argv[2],
717                                               argv[3], argv[4], argv[5],
718                                               argv[6]);
719 }
720
721 CAMLprim value
722 ocaml_libvirt_domain_block_stats (value domv, value pathv)
723 {
724   CAMLparam2 (domv, pathv);
725   CAMLlocal2 (rv,v);
726   virDomainPtr dom = Domain_val (domv);
727   char *path = String_val (pathv);
728   struct _virDomainBlockStats stats;
729   int r;
730
731   NONBLOCKING (r = virDomainBlockStats (dom, path, &stats, sizeof stats));
732   CHECK_ERROR (r == -1, "virDomainBlockStats");
733
734   rv = caml_alloc (5, 0);
735   v = caml_copy_int64 (stats.rd_req); Store_field (rv, 0, v);
736   v = caml_copy_int64 (stats.rd_bytes); Store_field (rv, 1, v);
737   v = caml_copy_int64 (stats.wr_req); Store_field (rv, 2, v);
738   v = caml_copy_int64 (stats.wr_bytes); Store_field (rv, 3, v);
739   v = caml_copy_int64 (stats.errs); Store_field (rv, 4, v);
740
741   CAMLreturn (rv);
742 }
743
744 CAMLprim value
745 ocaml_libvirt_domain_interface_stats (value domv, value pathv)
746 {
747   CAMLparam2 (domv, pathv);
748   CAMLlocal2 (rv,v);
749   virDomainPtr dom = Domain_val (domv);
750   char *path = String_val (pathv);
751   struct _virDomainInterfaceStats stats;
752   int r;
753
754   NONBLOCKING (r = virDomainInterfaceStats (dom, path, &stats, sizeof stats));
755   CHECK_ERROR (r == -1, "virDomainInterfaceStats");
756
757   rv = caml_alloc (8, 0);
758   v = caml_copy_int64 (stats.rx_bytes); Store_field (rv, 0, v);
759   v = caml_copy_int64 (stats.rx_packets); Store_field (rv, 1, v);
760   v = caml_copy_int64 (stats.rx_errs); Store_field (rv, 2, v);
761   v = caml_copy_int64 (stats.rx_drop); Store_field (rv, 3, v);
762   v = caml_copy_int64 (stats.tx_bytes); Store_field (rv, 4, v);
763   v = caml_copy_int64 (stats.tx_packets); Store_field (rv, 5, v);
764   v = caml_copy_int64 (stats.tx_errs); Store_field (rv, 6, v);
765   v = caml_copy_int64 (stats.tx_drop); Store_field (rv, 7, v);
766
767   CAMLreturn (rv);
768 }
769
770 CAMLprim value
771 ocaml_libvirt_domain_block_peek_native (value domv, value pathv, value offsetv, value sizev, value bufferv, value boffv)
772 {
773   CAMLparam5 (domv, pathv, offsetv, sizev, bufferv);
774   CAMLxparam1 (boffv);
775   virDomainPtr dom = Domain_val (domv);
776   const char *path = String_val (pathv);
777   unsigned long long offset = Int64_val (offsetv);
778   size_t size = Int_val (sizev);
779   char *buffer = String_val (bufferv);
780   int boff = Int_val (boffv);
781   int r;
782
783   /* Check that the return buffer is big enough. */
784   if (caml_string_length (bufferv) < boff + size)
785     caml_failwith ("virDomainBlockPeek: return buffer too short");
786
787   /* NB. not NONBLOCKING because buffer might move (XXX) */
788   r = virDomainBlockPeek (dom, path, offset, size, buffer+boff, 0);
789   CHECK_ERROR (r == -1, "virDomainBlockPeek");
790
791   CAMLreturn (Val_unit);
792 }
793
794 CAMLprim value
795 ocaml_libvirt_domain_block_peek_bytecode (value *argv, int argn)
796 {
797   return ocaml_libvirt_domain_block_peek_native (argv[0], argv[1], argv[2],
798                                                  argv[3], argv[4], argv[5]);
799 }
800
801 CAMLprim value
802 ocaml_libvirt_domain_memory_peek_native (value domv, value flagsv, value offsetv, value sizev, value bufferv, value boffv)
803 {
804   CAMLparam5 (domv, flagsv, offsetv, sizev, bufferv);
805   CAMLxparam1 (boffv);
806   CAMLlocal1 (flagv);
807   virDomainPtr dom = Domain_val (domv);
808   int flags = 0;
809   unsigned long long offset = Int64_val (offsetv);
810   size_t size = Int_val (sizev);
811   char *buffer = String_val (bufferv);
812   int boff = Int_val (boffv);
813   int r;
814
815   /* Check that the return buffer is big enough. */
816   if (caml_string_length (bufferv) < boff + size)
817     caml_failwith ("virDomainMemoryPeek: return buffer too short");
818
819   /* Do flags. */
820   for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1))
821     {
822       flagv = Field (flagsv, 0);
823       if (flagv == Val_int (0))
824         flags |= VIR_MEMORY_VIRTUAL;
825     }
826
827   /* NB. not NONBLOCKING because buffer might move (XXX) */
828   r = virDomainMemoryPeek (dom, offset, size, buffer+boff, flags);
829   CHECK_ERROR (r == -1, "virDomainMemoryPeek");
830
831   CAMLreturn (Val_unit);
832 }
833
834 CAMLprim value
835 ocaml_libvirt_domain_memory_peek_bytecode (value *argv, int argn)
836 {
837   return ocaml_libvirt_domain_memory_peek_native (argv[0], argv[1], argv[2],
838                                                   argv[3], argv[4], argv[5]);
839 }
840
841 /*----------------------------------------------------------------------*/
842
843 /* Domain events */
844
845 CAMLprim value
846 ocaml_libvirt_event_register_default_impl (value unitv)
847 {
848   CAMLparam1 (unitv);
849
850   /* arg is of type unit = void */
851   int r;
852
853   NONBLOCKING (r = virEventRegisterDefaultImpl ());
854   /* must be called before connection, therefore we can't use CHECK_ERROR */
855   if (r == -1) caml_failwith("virEventRegisterDefaultImpl");
856
857   CAMLreturn (Val_unit);
858 }
859
860 CAMLprim value
861 ocaml_libvirt_event_run_default_impl (value unitv)
862 {
863   CAMLparam1 (unitv);
864
865   /* arg is of type unit = void */
866   int r;
867
868   NONBLOCKING (r = virEventRunDefaultImpl ());
869   if (r == -1) caml_failwith("virEventRunDefaultImpl");
870
871   CAMLreturn (Val_unit);
872 }
873
874 /* We register a single C callback function for every distinct
875    callback signature. We encode the signature itself in the function
876    name and also in the name of the assocated OCaml callback
877    e.g.:
878       a C function called
879          i_i64_s_callback(virConnectPtr conn,
880                           virDomainPtr dom,
881                           int x,
882                           long y,
883                           char *z,
884                           void *opaque)
885       would correspond to an OCaml callback
886          Libvirt.i_i64_s_callback :
887            int64 -> [`R] Domain.t -> int -> int64 -> string option -> unit
888       where the initial int64 is a unique ID used by the OCaml to
889       dispatch to the specific OCaml closure and stored by libvirt
890       as the "opaque" data. */
891
892 /* Every one of the callbacks starts with a DOMAIN_CALLBACK_BEGIN(NAME)
893    where NAME is the string name of the OCaml callback registered
894    in libvirt.ml. */
895 #define DOMAIN_CALLBACK_BEGIN(NAME)                              \
896   value connv, domv, callback_id, result;                        \
897   connv = domv = callback_id = result = Val_int(0);              \
898   static value *callback = NULL;                                 \
899   caml_leave_blocking_section();                                 \
900   if (callback == NULL)                                          \
901     callback = caml_named_value(NAME);                           \
902   if (callback == NULL)                                          \
903     abort(); /* C code out of sync with OCaml code */            \
904   if ((virDomainRef(dom) == -1) || (virConnectRef(conn) == -1))  \
905     abort(); /* should never happen in practice? */              \
906                                                                  \
907   Begin_roots4(connv, domv, callback_id, result);                \
908   connv = Val_connect(conn);                                     \
909   domv = Val_domain(dom, connv);                                 \
910   callback_id = caml_copy_int64(*(long *)opaque);
911
912 /* Every one of the callbacks ends with a CALLBACK_END */
913 #define DOMAIN_CALLBACK_END                                      \
914   (void) caml_callback3(*callback, callback_id, domv, result);   \
915   End_roots();                                                   \
916   caml_enter_blocking_section();
917
918
919 static void
920 i_i_callback(virConnectPtr conn,
921              virDomainPtr dom,
922              int x,
923              int y,
924              void * opaque)
925 {
926   DOMAIN_CALLBACK_BEGIN("Libvirt.i_i_callback")
927   result = caml_alloc_tuple(2);
928   Store_field(result, 0, Val_int(x));
929   Store_field(result, 1, Val_int(y));
930   DOMAIN_CALLBACK_END
931 }
932
933 static void
934 u_callback(virConnectPtr conn,
935            virDomainPtr dom,
936            void *opaque)
937 {
938   DOMAIN_CALLBACK_BEGIN("Libvirt.u_callback")
939   result = Val_int(0); /* () */
940   DOMAIN_CALLBACK_END
941 }
942
943 static void
944 i64_callback(virConnectPtr conn,
945              virDomainPtr dom,
946              long long int64,
947              void *opaque)
948 {
949   DOMAIN_CALLBACK_BEGIN("Libvirt.i64_callback")
950   result = caml_copy_int64(int64);
951   DOMAIN_CALLBACK_END
952 }
953
954 static void
955 i_callback(virConnectPtr conn,
956            virDomainPtr dom,
957            int x,
958            void *opaque)
959 {
960   DOMAIN_CALLBACK_BEGIN("Libvirt.i_callback")
961   result = Val_int(x);
962   DOMAIN_CALLBACK_END
963 }
964
965 static void
966 s_i_callback(virConnectPtr conn,
967              virDomainPtr dom,
968              char *x,
969              int y,
970              void * opaque)
971 {
972   DOMAIN_CALLBACK_BEGIN("Libvirt.s_i_callback")
973   result = caml_alloc_tuple(2);
974   Store_field(result, 0, 
975               Val_opt(x, (Val_ptr_t) caml_copy_string));
976   Store_field(result, 1, Val_int(y));
977   DOMAIN_CALLBACK_END
978 }
979
980 static void
981 s_i_i_callback(virConnectPtr conn,
982                virDomainPtr dom,
983                char *x,
984                int y,
985                int z,
986                void * opaque)
987 {
988   DOMAIN_CALLBACK_BEGIN("Libvirt.s_i_i_callback")
989   result = caml_alloc_tuple(3);
990   Store_field(result, 0, 
991               Val_opt(x, (Val_ptr_t) caml_copy_string));
992   Store_field(result, 1, Val_int(y));
993   Store_field(result, 2, Val_int(z));
994   DOMAIN_CALLBACK_END
995 }
996
997 static void
998 s_s_i_callback(virConnectPtr conn,
999                virDomainPtr dom,
1000                char *x,
1001                char *y,
1002                int z,
1003                void *opaque)
1004 {
1005   DOMAIN_CALLBACK_BEGIN("Libvirt.s_s_i_callback")
1006   result = caml_alloc_tuple(3);
1007   Store_field(result, 0, 
1008               Val_opt(x, (Val_ptr_t) caml_copy_string));
1009   Store_field(result, 1,
1010               Val_opt(y, (Val_ptr_t) caml_copy_string));
1011   Store_field(result, 2, Val_int(z));
1012   DOMAIN_CALLBACK_END
1013 }
1014
1015 static void
1016 s_s_i_s_callback(virConnectPtr conn,
1017                  virDomainPtr dom,
1018                  char *x,
1019                  char *y,
1020                  int z,
1021                  char *a,
1022                  void *opaque)
1023 {
1024   DOMAIN_CALLBACK_BEGIN("Libvirt.s_s_i_s_callback")
1025   result = caml_alloc_tuple(4);
1026   Store_field(result, 0, 
1027               Val_opt(x, (Val_ptr_t) caml_copy_string));
1028   Store_field(result, 1,
1029               Val_opt(y, (Val_ptr_t) caml_copy_string));
1030   Store_field(result, 2, Val_int(z));
1031   Store_field(result, 3,
1032               Val_opt(a, (Val_ptr_t) caml_copy_string));
1033   DOMAIN_CALLBACK_END
1034 }
1035
1036 static void
1037 s_s_s_i_callback(virConnectPtr conn,
1038                  virDomainPtr dom,
1039                  char * x,
1040                  char * y,
1041                  char * z,
1042                  int a,
1043                  void * opaque)
1044 {
1045   DOMAIN_CALLBACK_BEGIN("Libvirt.s_s_s_i_callback")
1046   result = caml_alloc_tuple(4);
1047   Store_field(result, 0,
1048               Val_opt(x, (Val_ptr_t) caml_copy_string));
1049   Store_field(result, 1,
1050               Val_opt(y, (Val_ptr_t) caml_copy_string));
1051   Store_field(result, 2,
1052               Val_opt(z, (Val_ptr_t) caml_copy_string));
1053   Store_field(result, 3, Val_int(a));
1054   DOMAIN_CALLBACK_END
1055 }
1056
1057 static value
1058 Val_event_graphics_address(virDomainEventGraphicsAddressPtr x)
1059 {
1060   CAMLparam0 ();
1061   CAMLlocal1(result);
1062   result = caml_alloc_tuple(3);
1063   Store_field(result, 0, Val_int(x->family));
1064   Store_field(result, 1,
1065               Val_opt((void *) x->node, (Val_ptr_t) caml_copy_string));
1066   Store_field(result, 2,
1067               Val_opt((void *) x->service, (Val_ptr_t) caml_copy_string));
1068   CAMLreturn(result);
1069 }
1070
1071 static value
1072 Val_event_graphics_subject_identity(virDomainEventGraphicsSubjectIdentityPtr x)
1073 {
1074   CAMLparam0 ();
1075   CAMLlocal1(result);
1076   result = caml_alloc_tuple(2);
1077   Store_field(result, 0,
1078               Val_opt((void *) x->type, (Val_ptr_t) caml_copy_string));
1079   Store_field(result, 1,
1080               Val_opt((void *) x->name, (Val_ptr_t) caml_copy_string));
1081   CAMLreturn(result);
1082
1083 }
1084
1085 static value
1086 Val_event_graphics_subject(virDomainEventGraphicsSubjectPtr x)
1087 {
1088   CAMLparam0 ();
1089   CAMLlocal1(result);
1090   int i;
1091   result = caml_alloc_tuple(x->nidentity);
1092   for (i = 0; i < x->nidentity; i++ )
1093     Store_field(result, i,
1094                 Val_event_graphics_subject_identity(x->identities + i));
1095   CAMLreturn(result);
1096 }
1097
1098 static void
1099 i_ga_ga_s_gs_callback(virConnectPtr conn,
1100                       virDomainPtr dom,
1101                       int i1,
1102                       virDomainEventGraphicsAddressPtr ga1,
1103                       virDomainEventGraphicsAddressPtr ga2,
1104                       char *s1,
1105                       virDomainEventGraphicsSubjectPtr gs1,
1106                       void * opaque)
1107 {
1108   DOMAIN_CALLBACK_BEGIN("Libvirt.i_ga_ga_s_gs_callback")
1109   result = caml_alloc_tuple(5);
1110   Store_field(result, 0, Val_int(i1));
1111   Store_field(result, 1, Val_event_graphics_address(ga1));
1112   Store_field(result, 2, Val_event_graphics_address(ga2)); 
1113   Store_field(result, 3,
1114               Val_opt(s1, (Val_ptr_t) caml_copy_string));
1115   Store_field(result, 4, Val_event_graphics_subject(gs1));
1116   DOMAIN_CALLBACK_END
1117 }
1118
1119 static void
1120 timeout_callback(int timer, void *opaque)
1121 {
1122   value callback_id, result;
1123   callback_id = result = Val_int(0);
1124   static value *callback = NULL;
1125   caml_leave_blocking_section();
1126   if (callback == NULL)
1127     callback = caml_named_value("Libvirt.timeout_callback");
1128   if (callback == NULL)
1129     abort(); /* C code out of sync with OCaml code */
1130
1131   Begin_roots2(callback_id, result);
1132   callback_id = caml_copy_int64(*(long *)opaque);
1133
1134   (void)caml_callback_exn(*callback, callback_id);
1135   End_roots();
1136   caml_enter_blocking_section();
1137 }
1138
1139 CAMLprim value
1140 ocaml_libvirt_event_add_timeout (value connv, value ms, value callback_id)
1141 {
1142   CAMLparam3 (connv, ms, callback_id);
1143   void *opaque;
1144   virFreeCallback freecb = free;
1145   virEventTimeoutCallback cb = timeout_callback;
1146
1147   int r;
1148
1149   /* Store the int64 callback_id as the opaque data so the OCaml
1150      callback can demultiplex to the correct OCaml handler. */
1151   if ((opaque = malloc(sizeof(long))) == NULL)
1152     caml_failwith ("virEventAddTimeout: malloc");
1153   *((long*)opaque) = Int64_val(callback_id);
1154   NONBLOCKING(r = virEventAddTimeout(Int_val(ms), cb, opaque, freecb));
1155   CHECK_ERROR(r == -1, "virEventAddTimeout");
1156
1157   CAMLreturn(Val_int(r));
1158 }
1159
1160 CAMLprim value
1161 ocaml_libvirt_event_remove_timeout (value connv, value timer_id)
1162 {
1163   CAMLparam2 (connv, timer_id);
1164   int r;
1165
1166   NONBLOCKING(r = virEventRemoveTimeout(Int_val(timer_id)));
1167   CHECK_ERROR(r == -1, "virEventRemoveTimeout");
1168
1169   CAMLreturn(Val_int(r));
1170 }
1171
1172 CAMLprim value
1173 ocaml_libvirt_connect_domain_event_register_any(value connv, value domv, value callback, value callback_id)
1174 {
1175   CAMLparam4(connv, domv, callback, callback_id);
1176
1177   virConnectPtr conn = Connect_val (connv);
1178   virDomainPtr dom = NULL;
1179   int eventID = Tag_val(callback);
1180
1181   virConnectDomainEventGenericCallback cb;
1182   void *opaque;
1183   virFreeCallback freecb = free;
1184   int r;
1185
1186   if (domv != Val_int(0))
1187     dom = Domain_val (Field(domv, 0));
1188
1189   switch (eventID){
1190   case VIR_DOMAIN_EVENT_ID_LIFECYCLE:
1191     cb = VIR_DOMAIN_EVENT_CALLBACK(i_i_callback);
1192     break;
1193   case VIR_DOMAIN_EVENT_ID_REBOOT:
1194     cb = VIR_DOMAIN_EVENT_CALLBACK(u_callback);
1195     break;
1196   case VIR_DOMAIN_EVENT_ID_RTC_CHANGE:
1197     cb = VIR_DOMAIN_EVENT_CALLBACK(i64_callback);
1198     break;
1199   case VIR_DOMAIN_EVENT_ID_WATCHDOG:
1200     cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
1201     break;
1202   case VIR_DOMAIN_EVENT_ID_IO_ERROR:
1203     cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_i_callback);
1204     break;
1205   case VIR_DOMAIN_EVENT_ID_GRAPHICS:
1206     cb = VIR_DOMAIN_EVENT_CALLBACK(i_ga_ga_s_gs_callback);
1207     break;
1208   case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON:
1209     cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_i_s_callback);
1210     break;
1211   case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR:
1212     cb = VIR_DOMAIN_EVENT_CALLBACK(u_callback);
1213     break;
1214   case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
1215     cb = VIR_DOMAIN_EVENT_CALLBACK(s_i_i_callback);
1216     break;
1217   case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
1218     cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_s_i_callback);
1219     break;
1220   case VIR_DOMAIN_EVENT_ID_TRAY_CHANGE:
1221     cb = VIR_DOMAIN_EVENT_CALLBACK(s_i_callback);
1222     break;
1223   case VIR_DOMAIN_EVENT_ID_PMWAKEUP:
1224     cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
1225     break;
1226   case VIR_DOMAIN_EVENT_ID_PMSUSPEND:
1227     cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
1228     break;
1229   case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE:
1230     cb = VIR_DOMAIN_EVENT_CALLBACK(i64_callback);
1231     break;
1232   case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK:
1233     cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
1234     break;
1235   default:
1236     caml_failwith("vifConnectDomainEventRegisterAny: unimplemented eventID");
1237   }
1238
1239   /* Store the int64 callback_id as the opaque data so the OCaml
1240      callback can demultiplex to the correct OCaml handler. */
1241   if ((opaque = malloc(sizeof(long))) == NULL)
1242     caml_failwith ("virConnectDomainEventRegisterAny: malloc");
1243   *((long*)opaque) = Int64_val(callback_id);
1244   NONBLOCKING(r = virConnectDomainEventRegisterAny(conn, dom, eventID, cb, opaque, freecb));
1245   CHECK_ERROR(r == -1, "virConnectDomainEventRegisterAny");
1246
1247   CAMLreturn(Val_int(r));
1248 }
1249
1250 CAMLprim value
1251 ocaml_libvirt_storage_pool_get_info (value poolv)
1252 {
1253   CAMLparam1 (poolv);
1254   CAMLlocal2 (rv, v);
1255   virStoragePoolPtr pool = Pool_val (poolv);
1256   virStoragePoolInfo info;
1257   int r;
1258
1259   NONBLOCKING (r = virStoragePoolGetInfo (pool, &info));
1260   CHECK_ERROR (r == -1, "virStoragePoolGetInfo");
1261
1262   rv = caml_alloc (4, 0);
1263   Store_field (rv, 0, Val_int (info.state));
1264   v = caml_copy_int64 (info.capacity); Store_field (rv, 1, v);
1265   v = caml_copy_int64 (info.allocation); Store_field (rv, 2, v);
1266   v = caml_copy_int64 (info.available); Store_field (rv, 3, v);
1267
1268   CAMLreturn (rv);
1269 }
1270
1271 CAMLprim value
1272 ocaml_libvirt_storage_vol_get_info (value volv)
1273 {
1274   CAMLparam1 (volv);
1275   CAMLlocal2 (rv, v);
1276   virStorageVolPtr vol = Volume_val (volv);
1277   virStorageVolInfo info;
1278   int r;
1279
1280   NONBLOCKING (r = virStorageVolGetInfo (vol, &info));
1281   CHECK_ERROR (r == -1, "virStorageVolGetInfo");
1282
1283   rv = caml_alloc (3, 0);
1284   Store_field (rv, 0, Val_int (info.type));
1285   v = caml_copy_int64 (info.capacity); Store_field (rv, 1, v);
1286   v = caml_copy_int64 (info.allocation); Store_field (rv, 2, v);
1287
1288   CAMLreturn (rv);
1289 }
1290
1291 /*----------------------------------------------------------------------*/
1292
1293 CAMLprim value
1294 ocaml_libvirt_virterror_get_last_error (value unitv)
1295 {
1296   CAMLparam1 (unitv);
1297   CAMLlocal1 (rv);
1298   virErrorPtr err = virGetLastError ();
1299
1300   rv = Val_opt (err, (Val_ptr_t) Val_virterror);
1301
1302   CAMLreturn (rv);
1303 }
1304
1305 CAMLprim value
1306 ocaml_libvirt_virterror_get_last_conn_error (value connv)
1307 {
1308   CAMLparam1 (connv);
1309   CAMLlocal1 (rv);
1310   virConnectPtr conn = Connect_val (connv);
1311
1312   rv = Val_opt (conn, (Val_ptr_t) Val_connect);
1313
1314   CAMLreturn (rv);
1315 }
1316
1317 CAMLprim value
1318 ocaml_libvirt_virterror_reset_last_error (value unitv)
1319 {
1320   CAMLparam1 (unitv);
1321   virResetLastError ();
1322   CAMLreturn (Val_unit);
1323 }
1324
1325 CAMLprim value
1326 ocaml_libvirt_virterror_reset_last_conn_error (value connv)
1327 {
1328   CAMLparam1 (connv);
1329   virConnectPtr conn = Connect_val (connv);
1330   virConnResetLastError (conn);
1331   CAMLreturn (Val_unit);
1332 }
1333
1334 /*----------------------------------------------------------------------*/
1335
1336 static void
1337 ignore_errors (void *user_data, virErrorPtr error)
1338 {
1339   /* do nothing */
1340 }
1341
1342 /* Initialise the library. */
1343 CAMLprim value
1344 ocaml_libvirt_init (value unit)
1345 {
1346   CAMLparam1 (unit);
1347
1348   virSetErrorFunc (NULL, ignore_errors);
1349   virInitialize ();
1350
1351   CAMLreturn (Val_unit);
1352 }