0fdcbacdf0ee4a8fd8748a180c9471781624a670
[virt-top.git] / libvirt / libvirt_c.c
1 /* OCaml bindings for libvirt.
2  * (C) Copyright 2007 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 #include "config.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <libvirt/libvirt.h>
27 #include <libvirt/virterror.h>
28
29 #include <caml/config.h>
30 #include <caml/alloc.h>
31 #include <caml/callback.h>
32 #include <caml/custom.h>
33 #include <caml/fail.h>
34 #include <caml/memory.h>
35 #include <caml/misc.h>
36 #include <caml/mlvalues.h>
37
38 static char *Optstring_val (value strv);
39 typedef value (*Val_ptr_t) (void *);
40 static value Val_opt (void *ptr, Val_ptr_t Val_ptr);
41 /*static value option_default (value option, value deflt);*/
42 static value _raise_virterror (virConnectPtr conn, const char *fn);
43 static value Val_virterror (virErrorPtr err);
44
45 #define CHECK_ERROR(cond, conn, fn) \
46   do { if (cond) _raise_virterror (conn, fn); } while (0)
47
48 #define NOT_SUPPORTED(fn)                       \
49   caml_invalid_argument (fn " not supported")
50
51 /* For more about weak symbols, see:
52  * http://kolpackov.net/pipermail/notes/2004-March/000006.html
53  * We are using this to do runtime detection of library functions
54  * so that if we dynamically link with an older version of
55  * libvirt than we were compiled against, it won't fail (provided
56  * libvirt >= 0.2.1 - we don't support anything older).
57  */
58 #ifdef __GNUC__
59 #ifdef linux
60 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
61 #define HAVE_WEAK_SYMBOLS 1
62 #endif
63 #endif
64 #endif
65
66 #ifdef HAVE_WEAK_SYMBOLS
67 #define WEAK_SYMBOL_CHECK(sym)                          \
68   do { if (!sym) NOT_SUPPORTED(#sym); } while (0)
69 #else
70 #define WEAK_SYMBOL_CHECK(sym)
71 #endif /* HAVE_WEAK_SYMBOLS */
72
73 #ifdef HAVE_WEAK_SYMBOLS
74 #ifdef HAVE_VIRCONNECTGETHOSTNAME
75 extern char *virConnectGetHostname (virConnectPtr conn)
76   __attribute__((weak));
77 #endif
78 #ifdef HAVE_VIRCONNECTGETURI
79 extern char *virConnectGetURI (virConnectPtr conn)
80   __attribute__((weak));
81 #endif
82 #ifdef HAVE_VIRDOMAINBLOCKSTATS
83 extern int virDomainBlockStats (virDomainPtr dom,
84                                 const char *path,
85                                 virDomainBlockStatsPtr stats,
86                                 size_t size)
87   __attribute__((weak));
88 #endif
89 #ifdef HAVE_VIRDOMAINGETSCHEDULERPARAMETERS
90 extern int virDomainGetSchedulerParameters (virDomainPtr domain,
91                                             virSchedParameterPtr params,
92                                             int *nparams)
93   __attribute__((weak));
94 #endif
95 #ifdef HAVE_VIRDOMAINGETSCHEDULERTYPE
96 extern char *virDomainGetSchedulerType(virDomainPtr domain,
97                                        int *nparams)
98   __attribute__((weak));
99 #endif
100 #ifdef HAVE_VIRDOMAININTERFACESTATS
101 extern int virDomainInterfaceStats (virDomainPtr dom,
102                                     const char *path,
103                                     virDomainInterfaceStatsPtr stats,
104                                     size_t size)
105   __attribute__((weak));
106 #endif
107 #ifdef HAVE_VIRDOMAINMIGRATE
108 extern virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
109                                       unsigned long flags, const char *dname,
110                                       const char *uri, unsigned long bandwidth)
111   __attribute__((weak));
112 #endif
113 #ifdef HAVE_VIRDOMAINSETSCHEDULERPARAMETERS
114 extern int virDomainSetSchedulerParameters (virDomainPtr domain,
115                                             virSchedParameterPtr params,
116                                             int nparams)
117   __attribute__((weak));
118 #endif
119 #endif /* HAVE_WEAK_SYMBOLS */
120
121 /*----------------------------------------------------------------------*/
122
123 CAMLprim value
124 ocaml_libvirt_get_version (value driverv, value unit)
125 {
126   CAMLparam2 (driverv, unit);
127   CAMLlocal1 (rv);
128   const char *driver = Optstring_val (driverv);
129   unsigned long libVer, typeVer = 0, *typeVer_ptr;
130   int r;
131
132   typeVer_ptr = driver ? &typeVer : NULL;
133   r = virGetVersion (&libVer, driver, typeVer_ptr);
134   CHECK_ERROR (r == -1, NULL, "virGetVersion");
135
136   rv = caml_alloc_tuple (2);
137   Store_field (rv, 0, Val_int (libVer));
138   Store_field (rv, 1, Val_int (typeVer));
139   CAMLreturn (rv);
140 }
141
142 /*----------------------------------------------------------------------*/
143
144 /* Some notes about the use of custom blocks to store virConnectPtr,
145  * virDomainPtr and virNetworkPtr.
146  *------------------------------------------------------------------
147  *
148  * Libvirt does some tricky reference counting to keep track of
149  * virConnectPtr's, virDomainPtr's and virNetworkPtr's.
150  *
151  * There is only one function which can return a virConnectPtr
152  * (virConnectOpen*) and that allocates a new one each time.
153  *
154  * virDomainPtr/virNetworkPtr's on the other hand can be returned
155  * repeatedly (for the same underlying domain/network), and we must
156  * keep track of each one and explicitly free it with virDomainFree
157  * or virNetworkFree.  If we lose track of one then the reference
158  * counting in libvirt will keep it open.  We therefore wrap these
159  * in a custom block with a finalizer function.
160  *
161  * We also have to allow the user to explicitly free them, in
162  * which case we set the pointer inside the custom block to NULL.
163  * The finalizer notices this and doesn't free the object.
164  *
165  * Domains and networks "belong to" a connection.  We have to avoid
166  * the situation like this:
167  *
168  *   let conn = Connect.open ... in
169  *   let dom = Domain.lookup_by_id conn 0 in
170  *   (* conn goes out of scope and is garbage collected *)
171  *   printf "dom name = %s\n" (Domain.get_name dom)
172  *
173  * The reason is that when conn is garbage collected, virConnectClose
174  * is called and any subsequent operations on dom will fail (in fact
175  * will probably segfault).  To stop this from happening, the OCaml
176  * wrappers store domains (and networks) as explicit (dom, conn)
177  * pairs.
178  *
179  * Further complication with virterror / exceptions: Virterror gives
180  * us virConnectPtr, virDomainPtr, virNetworkPtr pointers.  If we
181  * follow standard practice and wrap these up in blocks with
182  * finalizers then we'll end up double-freeing (in particular, calling
183  * virConnectClose at the wrong time).  So for virterror, we have
184  * "special" wrapper functions (Val_connect_no_finalize, etc.).
185  */
186
187 /* Unwrap a custom block. */
188 #define Connect_val(rv) (*((virConnectPtr *)Data_custom_val(rv)))
189 #define Dom_val(rv) (*((virDomainPtr *)Data_custom_val(rv)))
190 #define Net_val(rv) (*((virNetworkPtr *)Data_custom_val(rv)))
191
192 /* Wrap up a pointer to something in a custom block. */
193 static value Val_connect (virConnectPtr conn);
194 static value Val_dom (virDomainPtr dom);
195 static value Val_net (virNetworkPtr net);
196
197 /* ONLY for use by virterror wrappers. */
198 static value Val_connect_no_finalize (virConnectPtr conn);
199 static value Val_dom_no_finalize (virDomainPtr dom);
200 static value Val_net_no_finalize (virNetworkPtr net);
201
202 /* Domains and networks are stored as pairs (dom/net, conn), so have
203  * some convenience functions for unwrapping and wrapping them.
204  */
205 #define Domain_val(rv) (Dom_val(Field((rv),0)))
206 #define Network_val(rv) (Net_val(Field((rv),0)))
207 #define Connect_domv(rv) (Connect_val(Field((rv),1)))
208 #define Connect_netv(rv) (Connect_val(Field((rv),1)))
209
210 static value Val_domain (virDomainPtr dom, value connv);
211 static value Val_network (virNetworkPtr net, value connv);
212
213 /* ONLY for use by virterror wrappers. */
214 static value Val_domain_no_finalize (virDomainPtr dom, value connv);
215 static value Val_network_no_finalize (virNetworkPtr net, value connv);
216
217 /*----------------------------------------------------------------------*/
218
219 /* Connection object. */
220
221 CAMLprim value
222 ocaml_libvirt_connect_open (value namev, value unit)
223 {
224   CAMLparam2 (namev, unit);
225   CAMLlocal1 (rv);
226   const char *name = Optstring_val (namev);
227   virConnectPtr conn;
228
229   conn = virConnectOpen (name);
230   CHECK_ERROR (!conn, NULL, "virConnectOpen");
231
232   rv = Val_connect (conn);
233
234   CAMLreturn (rv);
235 }
236
237 CAMLprim value
238 ocaml_libvirt_connect_open_readonly (value namev, value unit)
239 {
240   CAMLparam2 (namev, unit);
241   CAMLlocal1 (rv);
242   const char *name = Optstring_val (namev);
243   virConnectPtr conn;
244
245   conn = virConnectOpenReadOnly (name);
246   CHECK_ERROR (!conn, NULL, "virConnectOpen");
247
248   rv = Val_connect (conn);
249
250   CAMLreturn (rv);
251 }
252
253 CAMLprim value
254 ocaml_libvirt_connect_close (value connv)
255 {
256   CAMLparam1 (connv);
257   virConnectPtr conn = Connect_val (connv);
258   int r;
259
260   r = virConnectClose (conn);
261   CHECK_ERROR (r == -1, conn, "virConnectClose");
262
263   /* So that we don't double-free in the finalizer: */
264   Connect_val (connv) = NULL;
265
266   CAMLreturn (Val_unit);
267 }
268
269 CAMLprim value
270 ocaml_libvirt_connect_get_type (value connv)
271 {
272   CAMLparam1 (connv);
273   CAMLlocal1 (rv);
274   virConnectPtr conn = Connect_val (connv);
275   const char *r;
276
277   r = virConnectGetType (conn);
278   CHECK_ERROR (!r, conn, "virConnectGetType");
279
280   rv = caml_copy_string (r);
281   CAMLreturn (rv);
282 }
283
284 CAMLprim value
285 ocaml_libvirt_connect_get_version (value connv)
286 {
287   CAMLparam1 (connv);
288   virConnectPtr conn = Connect_val (connv);
289   unsigned long hvVer;
290   int r;
291
292   r = virConnectGetVersion (conn, &hvVer);
293   CHECK_ERROR (r == -1, conn, "virConnectGetVersion");
294
295   CAMLreturn (Val_int (hvVer));
296 }
297
298 CAMLprim value
299 ocaml_libvirt_connect_get_hostname (value connv)
300 {
301 #ifdef HAVE_VIRCONNECTGETHOSTNAME
302   CAMLparam1 (connv);
303   CAMLlocal1 (rv);
304   virConnectPtr conn = Connect_val (connv);
305   char *r;
306
307   WEAK_SYMBOL_CHECK (virConnectGetHostname);
308   r = virConnectGetHostname (conn);
309   CHECK_ERROR (!r, conn, "virConnectGetHostname");
310
311   rv = caml_copy_string (r);
312   free (r);
313   CAMLreturn (rv);
314 #else
315   NOT_SUPPORTED ("virConnectGetHostname");
316 #endif
317 }
318
319 CAMLprim value
320 ocaml_libvirt_connect_get_uri (value connv)
321 {
322 #ifdef HAVE_VIRCONNECTGETURI
323   CAMLparam1 (connv);
324   CAMLlocal1 (rv);
325   virConnectPtr conn = Connect_val (connv);
326   char *r;
327
328   WEAK_SYMBOL_CHECK (virConnectGetURI);
329   r = virConnectGetURI (conn);
330   CHECK_ERROR (!r, conn, "virConnectGetURI");
331
332   rv = caml_copy_string (r);
333   free (r);
334   CAMLreturn (rv);
335 #else
336   NOT_SUPPORTED ("virConnectGetURI");
337 #endif
338 }
339
340 CAMLprim value
341 ocaml_libvirt_connect_get_max_vcpus (value connv, value typev)
342 {
343   CAMLparam2 (connv, typev);
344   virConnectPtr conn = Connect_val (connv);
345   const char *type = Optstring_val (typev);
346   int r;
347
348   r = virConnectGetMaxVcpus (conn, type);
349   CHECK_ERROR (r == -1, conn, "virConnectGetMaxVcpus");
350
351   CAMLreturn (Val_int (r));
352 }
353
354 CAMLprim value
355 ocaml_libvirt_connect_list_domains (value connv, value iv)
356 {
357   CAMLparam2 (connv, iv);
358   CAMLlocal1 (rv);
359   virConnectPtr conn = Connect_val (connv);
360   int i = Int_val (iv);
361   int ids[i], r;
362
363   r = virConnectListDomains (conn, ids, i);
364   CHECK_ERROR (r == -1, conn, "virConnectListDomains");
365
366   rv = caml_alloc (r, 0);
367   for (i = 0; i < r; ++i)
368     Store_field (rv, i, Val_int (ids[i]));
369
370   CAMLreturn (rv);
371 }
372
373 CAMLprim value
374 ocaml_libvirt_connect_num_of_domains (value connv)
375 {
376   CAMLparam1 (connv);
377   virConnectPtr conn = Connect_val (connv);
378   int r;
379
380   r = virConnectNumOfDomains (conn);
381   CHECK_ERROR (r == -1, conn, "virConnectNumOfDomains");
382
383   CAMLreturn (Val_int (r));
384 }
385
386 CAMLprim value
387 ocaml_libvirt_connect_get_capabilities (value connv)
388 {
389   CAMLparam1 (connv);
390   CAMLlocal1 (rv);
391   virConnectPtr conn = Connect_val (connv);
392   char *r;
393
394   r = virConnectGetCapabilities (conn);
395   CHECK_ERROR (!r, conn, "virConnectGetCapabilities");
396
397   rv = caml_copy_string (r);
398   free (r);
399
400   CAMLreturn (rv);
401 }
402
403 CAMLprim value
404 ocaml_libvirt_connect_num_of_defined_domains (value connv)
405 {
406   CAMLparam1 (connv);
407   virConnectPtr conn = Connect_val (connv);
408   int r;
409
410   r = virConnectNumOfDefinedDomains (conn);
411   CHECK_ERROR (r == -1, conn, "virConnectNumOfDefinedDomains");
412
413   CAMLreturn (Val_int (r));
414 }
415
416 CAMLprim value
417 ocaml_libvirt_connect_list_defined_domains (value connv, value iv)
418 {
419   CAMLparam2 (connv, iv);
420   CAMLlocal2 (rv, strv);
421   virConnectPtr conn = Connect_val (connv);
422   int i = Int_val (iv);
423   char *names[i];
424   int r;
425
426   r = virConnectListDefinedDomains (conn, names, i);
427   CHECK_ERROR (r == -1, conn, "virConnectListDefinedDomains");
428
429   rv = caml_alloc (r, 0);
430   for (i = 0; i < r; ++i) {
431     strv = caml_copy_string (names[i]);
432     Store_field (rv, i, strv);
433     free (names[i]);
434   }
435
436   CAMLreturn (rv);
437 }
438
439 CAMLprim value
440 ocaml_libvirt_connect_num_of_networks (value connv)
441 {
442   CAMLparam1 (connv);
443   virConnectPtr conn = Connect_val (connv);
444   int r;
445
446   r = virConnectNumOfNetworks (conn);
447   CHECK_ERROR (r == -1, conn, "virConnectNumOfNetworks");
448
449   CAMLreturn (Val_int (r));
450 }
451
452 CAMLprim value
453 ocaml_libvirt_connect_list_networks (value connv, value iv)
454 {
455   CAMLparam2 (connv, iv);
456   CAMLlocal2 (rv, strv);
457   virConnectPtr conn = Connect_val (connv);
458   int i = Int_val (iv);
459   char *names[i];
460   int r;
461
462   r = virConnectListNetworks (conn, names, i);
463   CHECK_ERROR (r == -1, conn, "virConnectListNetworks");
464
465   rv = caml_alloc (r, 0);
466   for (i = 0; i < r; ++i) {
467     strv = caml_copy_string (names[i]);
468     Store_field (rv, i, strv);
469     free (names[i]);
470   }
471
472   CAMLreturn (rv);
473 }
474
475 CAMLprim value
476 ocaml_libvirt_connect_num_of_defined_networks (value connv)
477 {
478   CAMLparam1 (connv);
479   virConnectPtr conn = Connect_val (connv);
480   int r;
481
482   r = virConnectNumOfDefinedNetworks (conn);
483   CHECK_ERROR (r == -1, conn, "virConnectNumOfDefinedNetworks");
484
485   CAMLreturn (Val_int (r));
486 }
487
488 CAMLprim value
489 ocaml_libvirt_connect_list_defined_networks (value connv, value iv)
490 {
491   CAMLparam2 (connv, iv);
492   CAMLlocal2 (rv, strv);
493   virConnectPtr conn = Connect_val (connv);
494   int i = Int_val (iv);
495   char *names[i];
496   int r;
497
498   r = virConnectListDefinedNetworks (conn, names, i);
499   CHECK_ERROR (r == -1, conn, "virConnectListDefinedNetworks");
500
501   rv = caml_alloc (r, 0);
502   for (i = 0; i < r; ++i) {
503     strv = caml_copy_string (names[i]);
504     Store_field (rv, i, strv);
505     free (names[i]);
506   }
507
508   CAMLreturn (rv);
509 }
510
511 CAMLprim value
512 ocaml_libvirt_connect_get_node_info (value connv)
513 {
514   CAMLparam1 (connv);
515   CAMLlocal2 (rv, v);
516   virConnectPtr conn = Connect_val (connv);
517   virNodeInfo info;
518   int r;
519
520   r = virNodeGetInfo (conn, &info);
521   CHECK_ERROR (r == -1, conn, "virNodeGetInfo");
522
523   rv = caml_alloc (8, 0);
524   v = caml_copy_string (info.model); Store_field (rv, 0, v);
525   v = caml_copy_int64 (info.memory); Store_field (rv, 1, v);
526   Store_field (rv, 2, Val_int (info.cpus));
527   Store_field (rv, 3, Val_int (info.mhz));
528   Store_field (rv, 4, Val_int (info.nodes));
529   Store_field (rv, 5, Val_int (info.sockets));
530   Store_field (rv, 6, Val_int (info.cores));
531   Store_field (rv, 7, Val_int (info.threads));
532
533   CAMLreturn (rv);
534 }
535
536 CAMLprim value
537 ocaml_libvirt_domain_create_linux (value connv, value xmlv)
538 {
539   CAMLparam2 (connv, xmlv);
540   CAMLlocal1 (rv);
541   virConnectPtr conn = Connect_val (connv);
542   char *xml = String_val (xmlv);
543   virDomainPtr r;
544
545   r = virDomainCreateLinux (conn, xml, 0);
546   CHECK_ERROR (!r, conn, "virDomainCreateLinux");
547
548   rv = Val_domain (r, connv);
549   CAMLreturn (rv);
550 }
551
552 CAMLprim value
553 ocaml_libvirt_domain_lookup_by_id (value connv, value iv)
554 {
555   CAMLparam2 (connv, iv);
556   CAMLlocal1 (rv);
557   virConnectPtr conn = Connect_val (connv);
558   int i = Int_val (iv);
559   virDomainPtr r;
560
561   r = virDomainLookupByID (conn, i);
562   CHECK_ERROR (!r, conn, "virDomainLookupByID");
563
564   rv = Val_domain (r, connv);
565   CAMLreturn (rv);
566 }
567
568 CAMLprim value
569 ocaml_libvirt_domain_lookup_by_uuid (value connv, value uuidv)
570 {
571   CAMLparam2 (connv, uuidv);
572   CAMLlocal1 (rv);
573   virConnectPtr conn = Connect_val (connv);
574   char *uuid = String_val (uuidv);
575   virDomainPtr r;
576
577   r = virDomainLookupByUUID (conn, (unsigned char *) uuid);
578   CHECK_ERROR (!r, conn, "virDomainLookupByUUID");
579
580   rv = Val_domain (r, connv);
581   CAMLreturn (rv);
582 }
583
584 CAMLprim value
585 ocaml_libvirt_domain_lookup_by_uuid_string (value connv, value uuidv)
586 {
587   CAMLparam2 (connv, uuidv);
588   CAMLlocal1 (rv);
589   virConnectPtr conn = Connect_val (connv);
590   char *uuid = String_val (uuidv);
591   virDomainPtr r;
592
593   r = virDomainLookupByUUIDString (conn, uuid);
594   CHECK_ERROR (!r, conn, "virDomainLookupByUUIDString");
595
596   rv = Val_domain (r, connv);
597   CAMLreturn (rv);
598 }
599
600 CAMLprim value
601 ocaml_libvirt_domain_lookup_by_name (value connv, value namev)
602 {
603   CAMLparam2 (connv, namev);
604   CAMLlocal1 (rv);
605   virConnectPtr conn = Connect_val (connv);
606   char *name = String_val (namev);
607   virDomainPtr r;
608
609   r = virDomainLookupByName (conn, name);
610   CHECK_ERROR (!r, conn, "virDomainLookupByName");
611
612   rv = Val_domain (r, connv);
613   CAMLreturn (rv);
614 }
615
616 CAMLprim value
617 ocaml_libvirt_domain_destroy (value domv)
618 {
619   CAMLparam1 (domv);
620   virDomainPtr dom = Domain_val (domv);
621   virConnectPtr conn = Connect_domv (domv);
622   int r;
623
624   r = virDomainDestroy (dom);
625   CHECK_ERROR (r == -1, conn, "virDomainDestroy");
626
627   /* So that we don't double-free in the finalizer: */
628   Domain_val (domv) = NULL;
629
630   CAMLreturn (Val_unit);
631 }
632
633 CAMLprim value
634 ocaml_libvirt_domain_free (value domv)
635 {
636   CAMLparam1 (domv);
637   virDomainPtr dom = Domain_val (domv);
638   virConnectPtr conn = Connect_domv (domv);
639   int r;
640
641   r = virDomainFree (dom);
642   CHECK_ERROR (r == -1, conn, "virDomainFree");
643
644   /* So that we don't double-free in the finalizer: */
645   Domain_val (domv) = NULL;
646
647   CAMLreturn (Val_unit);
648 }
649
650 CAMLprim value
651 ocaml_libvirt_domain_suspend (value domv)
652 {
653   CAMLparam1 (domv);
654   virDomainPtr dom = Domain_val (domv);
655   virConnectPtr conn = Connect_domv (domv);
656   int r;
657
658   r = virDomainSuspend (dom);
659   CHECK_ERROR (r == -1, conn, "virDomainSuspend");
660
661   CAMLreturn (Val_unit);
662 }
663
664 CAMLprim value
665 ocaml_libvirt_domain_resume (value domv)
666 {
667   CAMLparam1 (domv);
668   virDomainPtr dom = Domain_val (domv);
669   virConnectPtr conn = Connect_domv (domv);
670   int r;
671
672   r = virDomainResume (dom);
673   CHECK_ERROR (r == -1, conn, "virDomainResume");
674
675   CAMLreturn (Val_unit);
676 }
677
678 CAMLprim value
679 ocaml_libvirt_domain_save (value domv, value pathv)
680 {
681   CAMLparam2 (domv, pathv);
682   virDomainPtr dom = Domain_val (domv);
683   virConnectPtr conn = Connect_domv (domv);
684   char *path = String_val (pathv);
685   int r;
686
687   r = virDomainSave (dom, path);
688   CHECK_ERROR (r == -1, conn, "virDomainSave");
689
690   CAMLreturn (Val_unit);
691 }
692
693 CAMLprim value
694 ocaml_libvirt_domain_restore (value connv, value pathv)
695 {
696   CAMLparam2 (connv, pathv);
697   virConnectPtr conn = Connect_val (connv);
698   char *path = String_val (pathv);
699   int r;
700
701   r = virDomainRestore (conn, path);
702   CHECK_ERROR (r == -1, conn, "virDomainRestore");
703
704   CAMLreturn (Val_unit);
705 }
706
707 CAMLprim value
708 ocaml_libvirt_domain_core_dump (value domv, value pathv)
709 {
710   CAMLparam2 (domv, pathv);
711   virDomainPtr dom = Domain_val (domv);
712   virConnectPtr conn = Connect_domv (domv);
713   char *path = String_val (pathv);
714   int r;
715
716   r = virDomainCoreDump (dom, path, 0);
717   CHECK_ERROR (r == -1, conn, "virDomainCoreDump");
718
719   CAMLreturn (Val_unit);
720 }
721
722 CAMLprim value
723 ocaml_libvirt_domain_shutdown (value domv)
724 {
725   CAMLparam1 (domv);
726   virDomainPtr dom = Domain_val (domv);
727   virConnectPtr conn = Connect_domv (domv);
728   int r;
729
730   r = virDomainShutdown (dom);
731   CHECK_ERROR (r == -1, conn, "virDomainShutdown");
732
733   CAMLreturn (Val_unit);
734 }
735
736 CAMLprim value
737 ocaml_libvirt_domain_reboot (value domv)
738 {
739   CAMLparam1 (domv);
740   virDomainPtr dom = Domain_val (domv);
741   virConnectPtr conn = Connect_domv (domv);
742   int r;
743
744   r = virDomainReboot (dom, 0);
745   CHECK_ERROR (r == -1, conn, "virDomainReboot");
746
747   CAMLreturn (Val_unit);
748 }
749
750 CAMLprim value
751 ocaml_libvirt_domain_get_name (value domv)
752 {
753   CAMLparam1 (domv);
754   CAMLlocal1 (rv);
755   virDomainPtr dom = Domain_val (domv);
756   virConnectPtr conn = Connect_domv (domv);
757   const char *r;
758
759   r = virDomainGetName (dom);
760   CHECK_ERROR (!r, conn, "virDomainGetName");
761
762   rv = caml_copy_string (r);
763   CAMLreturn (rv);
764 }
765
766 CAMLprim value
767 ocaml_libvirt_domain_get_uuid (value domv)
768 {
769   CAMLparam1 (domv);
770   CAMLlocal1 (rv);
771   virDomainPtr dom = Domain_val (domv);
772   virConnectPtr conn = Connect_domv (domv);
773   unsigned char uuid[VIR_UUID_BUFLEN];
774   int r;
775
776   r = virDomainGetUUID (dom, uuid);
777   CHECK_ERROR (r == -1, conn, "virDomainGetUUID");
778
779   rv = caml_copy_string ((char *) uuid);
780   CAMLreturn (rv);
781 }
782
783 CAMLprim value
784 ocaml_libvirt_domain_get_uuid_string (value domv)
785 {
786   CAMLparam1 (domv);
787   CAMLlocal1 (rv);
788   virDomainPtr dom = Domain_val (domv);
789   virConnectPtr conn = Connect_domv (domv);
790   char uuid[VIR_UUID_STRING_BUFLEN];
791   int r;
792
793   r = virDomainGetUUIDString (dom, uuid);
794   CHECK_ERROR (r == -1, conn, "virDomainGetUUIDString");
795
796   rv = caml_copy_string (uuid);
797   CAMLreturn (rv);
798 }
799
800 CAMLprim value
801 ocaml_libvirt_domain_get_id (value domv)
802 {
803   CAMLparam1 (domv);
804   virDomainPtr dom = Domain_val (domv);
805   virConnectPtr conn = Connect_domv (domv);
806   unsigned int r;
807
808   r = virDomainGetID (dom);
809   /* There's a bug in libvirt which means that if you try to get
810    * the ID of a defined-but-not-running domain, it returns -1,
811    * and there's no way to distinguish that from an error.
812    */
813   CHECK_ERROR (r == (unsigned int) -1, conn, "virDomainGetID");
814
815   CAMLreturn (Val_int ((int) r));
816 }
817
818 CAMLprim value
819 ocaml_libvirt_domain_get_os_type (value domv)
820 {
821   CAMLparam1 (domv);
822   CAMLlocal1 (rv);
823   virDomainPtr dom = Domain_val (domv);
824   virConnectPtr conn = Connect_domv (domv);
825   char *r;
826
827   r = virDomainGetOSType (dom);
828   CHECK_ERROR (!r, conn, "virDomainGetOSType");
829
830   rv = caml_copy_string (r);
831   free (r);
832   CAMLreturn (rv);
833 }
834
835 CAMLprim value
836 ocaml_libvirt_domain_get_max_memory (value domv)
837 {
838   CAMLparam1 (domv);
839   CAMLlocal1 (rv);
840   virDomainPtr dom = Domain_val (domv);
841   virConnectPtr conn = Connect_domv (domv);
842   unsigned long r;
843
844   r = virDomainGetMaxMemory (dom);
845   CHECK_ERROR (r == 0 /* [sic] */, conn, "virDomainGetMaxMemory");
846
847   rv = caml_copy_int64 (r);
848   CAMLreturn (rv);
849 }
850
851 CAMLprim value
852 ocaml_libvirt_domain_set_max_memory (value domv, value memv)
853 {
854   CAMLparam2 (domv, memv);
855   virDomainPtr dom = Domain_val (domv);
856   virConnectPtr conn = Connect_domv (domv);
857   unsigned long mem = Int64_val (memv);
858   int r;
859
860   r = virDomainSetMaxMemory (dom, mem);
861   CHECK_ERROR (r == -1, conn, "virDomainSetMaxMemory");
862
863   CAMLreturn (Val_unit);
864 }
865
866 CAMLprim value
867 ocaml_libvirt_domain_set_memory (value domv, value memv)
868 {
869   CAMLparam2 (domv, memv);
870   virDomainPtr dom = Domain_val (domv);
871   virConnectPtr conn = Connect_domv (domv);
872   unsigned long mem = Int64_val (memv);
873   int r;
874
875   r = virDomainSetMemory (dom, mem);
876   CHECK_ERROR (r == -1, conn, "virDomainSetMemory");
877
878   CAMLreturn (Val_unit);
879 }
880
881 CAMLprim value
882 ocaml_libvirt_domain_get_info (value domv)
883 {
884   CAMLparam1 (domv);
885   CAMLlocal2 (rv, v);
886   virDomainPtr dom = Domain_val (domv);
887   virConnectPtr conn = Connect_domv (domv);
888   virDomainInfo info;
889   int r;
890
891   r = virDomainGetInfo (dom, &info);
892   CHECK_ERROR (r == -1, conn, "virDomainGetInfo");
893
894   rv = caml_alloc (5, 0);
895   Store_field (rv, 0, Val_int (info.state)); // These flags are compatible.
896   v = caml_copy_int64 (info.maxMem); Store_field (rv, 1, v);
897   v = caml_copy_int64 (info.memory); Store_field (rv, 2, v);
898   Store_field (rv, 3, Val_int (info.nrVirtCpu));
899   v = caml_copy_int64 (info.cpuTime); Store_field (rv, 4, v);
900
901   CAMLreturn (rv);
902 }
903
904 CAMLprim value
905 ocaml_libvirt_domain_get_xml_desc (value domv)
906 {
907   CAMLparam1 (domv);
908   CAMLlocal1 (rv);
909   virDomainPtr dom = Domain_val (domv);
910   virConnectPtr conn = Connect_domv (domv);
911   char *r;
912
913   r = virDomainGetXMLDesc (dom, 0);
914   CHECK_ERROR (!r, conn, "virDomainGetXMLDesc");
915
916   rv = caml_copy_string (r);
917   free (r);
918   CAMLreturn (rv);
919 }
920
921 CAMLprim value
922 ocaml_libvirt_domain_get_scheduler_type (value domv)
923 {
924 #ifdef HAVE_VIRDOMAINGETSCHEDULERTYPE
925   CAMLparam1 (domv);
926   CAMLlocal2 (rv, strv);
927   virDomainPtr dom = Domain_val (domv);
928   virConnectPtr conn = Connect_domv (domv);
929   char *r;
930   int nparams;
931
932   WEAK_SYMBOL_CHECK (virDomainGetSchedulerType);
933   r = virDomainGetSchedulerType (dom, &nparams);
934   CHECK_ERROR (!r, conn, "virDomainGetSchedulerType");
935
936   rv = caml_alloc_tuple (2);
937   strv = caml_copy_string (r); Store_field (rv, 0, strv);
938   free (r);
939   Store_field (rv, 1, nparams);
940   CAMLreturn (rv);
941 #else
942   NOT_SUPPORTED ("virDomainGetSchedulerType");
943 #endif
944 }
945
946 CAMLprim value
947 ocaml_libvirt_domain_get_scheduler_parameters (value domv, value nparamsv)
948 {
949 #ifdef HAVE_VIRDOMAINGETSCHEDULERPARAMETERS
950   CAMLparam2 (domv, nparamsv);
951   CAMLlocal4 (rv, v, v2, v3);
952   virDomainPtr dom = Domain_val (domv);
953   virConnectPtr conn = Connect_domv (domv);
954   int nparams = Int_val (nparamsv);
955   virSchedParameter params[nparams];
956   int r, i;
957
958   WEAK_SYMBOL_CHECK (virDomainGetSchedulerParameters);
959   r = virDomainGetSchedulerParameters (dom, params, &nparams);
960   CHECK_ERROR (r == -1, conn, "virDomainGetSchedulerParameters");
961
962   rv = caml_alloc (nparams, 0);
963   for (i = 0; i < nparams; ++i) {
964     v = caml_alloc_tuple (2); Store_field (rv, i, v);
965     v2 = caml_copy_string (params[i].field); Store_field (v, 0, v2);
966     switch (params[i].type) {
967     case VIR_DOMAIN_SCHED_FIELD_INT:
968       v2 = caml_alloc (1, 0);
969       v3 = caml_copy_int32 (params[i].value.i); Store_field (v2, 0, v3);
970       break;
971     case VIR_DOMAIN_SCHED_FIELD_UINT:
972       v2 = caml_alloc (1, 1);
973       v3 = caml_copy_int32 (params[i].value.ui); Store_field (v2, 0, v3);
974       break;
975     case VIR_DOMAIN_SCHED_FIELD_LLONG:
976       v2 = caml_alloc (1, 2);
977       v3 = caml_copy_int64 (params[i].value.l); Store_field (v2, 0, v3);
978       break;
979     case VIR_DOMAIN_SCHED_FIELD_ULLONG:
980       v2 = caml_alloc (1, 3);
981       v3 = caml_copy_int64 (params[i].value.ul); Store_field (v2, 0, v3);
982       break;
983     case VIR_DOMAIN_SCHED_FIELD_DOUBLE:
984       v2 = caml_alloc (1, 4);
985       v3 = caml_copy_double (params[i].value.d); Store_field (v2, 0, v3);
986       break;
987     case VIR_DOMAIN_SCHED_FIELD_BOOLEAN:
988       v2 = caml_alloc (1, 5);
989       Store_field (v2, 0, Val_int (params[i].value.b));
990       break;
991     default:
992       caml_failwith ((char *)__FUNCTION__);
993     }
994     Store_field (v, 1, v2);
995   }
996   CAMLreturn (rv);
997 #else
998   NOT_SUPPORTED ("virDomainGetSchedulerParameters");
999 #endif
1000 }
1001
1002 CAMLprim value
1003 ocaml_libvirt_domain_set_scheduler_parameters (value domv, value paramsv)
1004 {
1005 #ifdef HAVE_VIRDOMAINSETSCHEDULERPARAMETERS
1006   CAMLparam2 (domv, paramsv);
1007   CAMLlocal1 (v);
1008   virDomainPtr dom = Domain_val (domv);
1009   virConnectPtr conn = Connect_domv (domv);
1010   int nparams = Wosize_val (paramsv);
1011   virSchedParameter params[nparams];
1012   int r, i;
1013   char *name;
1014
1015   for (i = 0; i < nparams; ++i) {
1016     v = Field (paramsv, i);     /* Points to the two-element tuple. */
1017     name = String_val (Field (v, 0));
1018     strncpy (params[i].field, name, VIR_DOMAIN_SCHED_FIELD_LENGTH);
1019     params[i].field[VIR_DOMAIN_SCHED_FIELD_LENGTH-1] = '\0';
1020     v = Field (v, 1);           /* Points to the sched_param_value block. */
1021     switch (Tag_val (v)) {
1022     case 0:
1023       params[i].type = VIR_DOMAIN_SCHED_FIELD_INT;
1024       params[i].value.i = Int32_val (Field (v, 0));
1025       break;
1026     case 1:
1027       params[i].type = VIR_DOMAIN_SCHED_FIELD_UINT;
1028       params[i].value.ui = Int32_val (Field (v, 0));
1029       break;
1030     case 2:
1031       params[i].type = VIR_DOMAIN_SCHED_FIELD_LLONG;
1032       params[i].value.l = Int64_val (Field (v, 0));
1033       break;
1034     case 3:
1035       params[i].type = VIR_DOMAIN_SCHED_FIELD_ULLONG;
1036       params[i].value.ul = Int64_val (Field (v, 0));
1037       break;
1038     case 4:
1039       params[i].type = VIR_DOMAIN_SCHED_FIELD_DOUBLE;
1040       params[i].value.d = Double_val (Field (v, 0));
1041       break;
1042     case 5:
1043       params[i].type = VIR_DOMAIN_SCHED_FIELD_BOOLEAN;
1044       params[i].value.b = Int_val (Field (v, 0));
1045       break;
1046     default:
1047       caml_failwith ((char *)__FUNCTION__);
1048     }
1049   }
1050
1051   WEAK_SYMBOL_CHECK (virDomainSetSchedulerParameters);
1052   r = virDomainSetSchedulerParameters (dom, params, nparams);
1053   CHECK_ERROR (r == -1, conn, "virDomainSetSchedulerParameters");
1054
1055   CAMLreturn (Val_unit);
1056 #else
1057   NOT_SUPPORTED ("virDomainSetSchedulerParameters");
1058 #endif
1059 }
1060
1061 CAMLprim value
1062 ocaml_libvirt_domain_define_xml (value connv, value xmlv)
1063 {
1064   CAMLparam2 (connv, xmlv);
1065   CAMLlocal1 (rv);
1066   virConnectPtr conn = Connect_val (connv);
1067   char *xml = String_val (xmlv);
1068   virDomainPtr r;
1069
1070   r = virDomainDefineXML (conn, xml);
1071   CHECK_ERROR (!r, conn, "virDomainDefineXML");
1072
1073   rv = Val_domain (r, connv);
1074   CAMLreturn (rv);
1075 }
1076
1077 CAMLprim value
1078 ocaml_libvirt_domain_undefine (value domv)
1079 {
1080   CAMLparam1 (domv);
1081   virDomainPtr dom = Domain_val (domv);
1082   virConnectPtr conn = Connect_domv (domv);
1083   int r;
1084
1085   r = virDomainUndefine (dom);
1086   CHECK_ERROR (r == -1, conn, "virDomainUndefine");
1087
1088   CAMLreturn (Val_unit);
1089 }
1090
1091 CAMLprim value
1092 ocaml_libvirt_domain_create (value domv)
1093 {
1094   CAMLparam1 (domv);
1095   virDomainPtr dom = Domain_val (domv);
1096   virConnectPtr conn = Connect_domv (domv);
1097   int r;
1098
1099   r = virDomainCreate (dom);
1100   CHECK_ERROR (r == -1, conn, "virDomainCreate");
1101
1102   CAMLreturn (Val_unit);
1103 }
1104
1105 CAMLprim value
1106 ocaml_libvirt_domain_get_autostart (value domv)
1107 {
1108   CAMLparam1 (domv);
1109   virDomainPtr dom = Domain_val (domv);
1110   virConnectPtr conn = Connect_domv (domv);
1111   int r, autostart;
1112
1113   r = virDomainGetAutostart (dom, &autostart);
1114   CHECK_ERROR (r == -1, conn, "virDomainGetAutostart");
1115
1116   CAMLreturn (autostart ? Val_true : Val_false);
1117 }
1118
1119 CAMLprim value
1120 ocaml_libvirt_domain_set_autostart (value domv, value autostartv)
1121 {
1122   CAMLparam2 (domv, autostartv);
1123   virDomainPtr dom = Domain_val (domv);
1124   virConnectPtr conn = Connect_domv (domv);
1125   int r, autostart = autostartv == Val_true ? 1 : 0;
1126
1127   r = virDomainSetAutostart (dom, autostart);
1128   CHECK_ERROR (r == -1, conn, "virDomainSetAutostart");
1129
1130   CAMLreturn (Val_unit);
1131 }
1132
1133 CAMLprim value
1134 ocaml_libvirt_domain_set_vcpus (value domv, value nvcpusv)
1135 {
1136   CAMLparam2 (domv, nvcpusv);
1137   virDomainPtr dom = Domain_val (domv);
1138   virConnectPtr conn = Connect_domv (domv);
1139   int r, nvcpus = Int_val (nvcpusv);
1140
1141   r = virDomainSetVcpus (dom, nvcpus);
1142   CHECK_ERROR (r == -1, conn, "virDomainSetVcpus");
1143
1144   CAMLreturn (Val_unit);
1145 }
1146
1147 CAMLprim value
1148 ocaml_libvirt_domain_pin_vcpu (value domv, value vcpuv, value cpumapv)
1149 {
1150   CAMLparam3 (domv, vcpuv, cpumapv);
1151   virDomainPtr dom = Domain_val (domv);
1152   virConnectPtr conn = Connect_domv (domv);
1153   int maplen = caml_string_length (cpumapv);
1154   unsigned char *cpumap = (unsigned char *) String_val (cpumapv);
1155   int vcpu = Int_val (vcpuv);
1156   int r;
1157
1158   r = virDomainPinVcpu (dom, vcpu, cpumap, maplen);
1159   CHECK_ERROR (r == -1, conn, "virDomainPinVcpu");
1160
1161   CAMLreturn (Val_unit);
1162 }
1163
1164 CAMLprim value
1165 ocaml_libvirt_domain_get_vcpus (value domv, value maxinfov, value maplenv)
1166 {
1167   CAMLparam3 (domv, maxinfov, maplenv);
1168   CAMLlocal5 (rv, infov, strv, v, v2);
1169   virDomainPtr dom = Domain_val (domv);
1170   virConnectPtr conn = Connect_domv (domv);
1171   int maxinfo = Int_val (maxinfov);
1172   int maplen = Int_val (maplenv);
1173   virVcpuInfo info[maxinfo];
1174   unsigned char cpumaps[maxinfo * maplen];
1175   int r, i;
1176
1177   memset (info, 0, sizeof (virVcpuInfo) * maxinfo);
1178   memset (cpumaps, 0, maxinfo * maplen);
1179
1180   r = virDomainGetVcpus (dom, info, maxinfo, cpumaps, maplen);
1181   CHECK_ERROR (r == -1, conn, "virDomainPinVcpu");
1182
1183   /* Copy the virVcpuInfo structures. */
1184   infov = caml_alloc (maxinfo, 0);
1185   for (i = 0; i < maxinfo; ++i) {
1186     v2 = caml_alloc (4, 0); Store_field (infov, i, v2);
1187     Store_field (v2, 0, Val_int (info[i].number));
1188     Store_field (v2, 1, Val_int (info[i].state));
1189     v = caml_copy_int64 (info[i].cpuTime); Store_field (v2, 2, v);
1190     Store_field (v2, 3, Val_int (info[i].cpu));
1191   }
1192
1193   /* Copy the bitmap. */
1194   strv = caml_alloc_string (maxinfo * maplen);
1195   memcpy (String_val (strv), cpumaps, maxinfo * maplen);
1196
1197   /* Allocate the tuple and return it. */
1198   rv = caml_alloc_tuple (3);
1199   Store_field (rv, 0, Val_int (r)); /* number of CPUs. */
1200   Store_field (rv, 1, infov);
1201   Store_field (rv, 2, strv);
1202
1203   CAMLreturn (rv);
1204 }
1205
1206 CAMLprim value
1207 ocaml_libvirt_domain_get_max_vcpus (value domv)
1208 {
1209   CAMLparam1 (domv);
1210   virDomainPtr dom = Domain_val (domv);
1211   virConnectPtr conn = Connect_domv (domv);
1212   int r;
1213
1214   r = virDomainGetMaxVcpus (dom);
1215   CHECK_ERROR (r == -1, conn, "virDomainGetMaxVcpus");
1216
1217   CAMLreturn (Val_int (r));
1218 }
1219
1220 CAMLprim value
1221 ocaml_libvirt_domain_attach_device (value domv, value xmlv)
1222 {
1223   CAMLparam2 (domv, xmlv);
1224   virDomainPtr dom = Domain_val (domv);
1225   virConnectPtr conn = Connect_domv (domv);
1226   char *xml = String_val (xmlv);
1227   int r;
1228
1229   r = virDomainAttachDevice (dom, xml);
1230   CHECK_ERROR (r == -1, conn, "virDomainAttachDevice");
1231
1232   CAMLreturn (Val_unit);
1233 }
1234
1235 CAMLprim value
1236 ocaml_libvirt_domain_detach_device (value domv, value xmlv)
1237 {
1238   CAMLparam2 (domv, xmlv);
1239   virDomainPtr dom = Domain_val (domv);
1240   virConnectPtr conn = Connect_domv (domv);
1241   char *xml = String_val (xmlv);
1242   int r;
1243
1244   r = virDomainDetachDevice (dom, xml);
1245   CHECK_ERROR (r == -1, conn, "virDomainDetachDevice");
1246
1247   CAMLreturn (Val_unit);
1248 }
1249
1250 CAMLprim value
1251 ocaml_libvirt_domain_migrate_native (value domv, value dconnv, value flagsv, value optdnamev, value opturiv, value optbandwidthv, value unitv)
1252 {
1253 #ifdef HAVE_VIRDOMAINMIGRATE
1254   CAMLparam5 (domv, dconnv, flagsv, optdnamev, opturiv);
1255   CAMLxparam2 (optbandwidthv, unitv);
1256   CAMLlocal2 (flagv, rv);
1257   virDomainPtr dom = Domain_val (domv);
1258   virConnectPtr conn = Connect_domv (domv);
1259   virConnectPtr dconn = Connect_val (dconnv);
1260   int flags = 0;
1261   const char *dname = Optstring_val (optdnamev);
1262   const char *uri = Optstring_val (opturiv);
1263   unsigned long bandwidth;
1264   virDomainPtr r;
1265
1266   /* Iterate over the list of flags. */
1267   for (; flagsv != Val_int (0); flagsv = Field (flagsv, 1))
1268     {
1269       flagv = Field (flagsv, 0);
1270       if (flagv == Int_val(0))
1271         flags |= VIR_MIGRATE_LIVE;
1272     }
1273
1274   if (optbandwidthv == Val_int (0)) /* None */
1275     bandwidth = 0;
1276   else                          /* Some bandwidth */
1277     bandwidth = Int_val (Field (optbandwidthv, 0));
1278
1279   WEAK_SYMBOL_CHECK (virDomainMigrate);
1280   r = virDomainMigrate (dom, dconn, flags, dname, uri, bandwidth);
1281   CHECK_ERROR (!r, conn, "virDomainMigrate");
1282
1283   rv = Val_domain (r, dconnv);
1284
1285   CAMLreturn (rv);
1286
1287 #else /* virDomainMigrate not supported */
1288   NOT_SUPPORTED ("virDomainMigrate");
1289 #endif
1290 }
1291
1292 CAMLprim value
1293 ocaml_libvirt_domain_migrate_bytecode (value *argv, int argn)
1294 {
1295   return ocaml_libvirt_domain_migrate_native (argv[0], argv[1], argv[2],
1296                                               argv[3], argv[4], argv[5],
1297                                               argv[6]);
1298 }
1299
1300 CAMLprim value
1301 ocaml_libvirt_domain_block_stats (value domv, value pathv)
1302 {
1303 #if HAVE_VIRDOMAINBLOCKSTATS
1304   CAMLparam2 (domv, pathv);
1305   CAMLlocal2 (rv,v);
1306   virDomainPtr dom = Domain_val (domv);
1307   virConnectPtr conn = Connect_domv (domv);
1308   char *path = String_val (pathv);
1309   struct _virDomainBlockStats stats;
1310   int r;
1311
1312   WEAK_SYMBOL_CHECK (virDomainBlockStats);
1313   r = virDomainBlockStats (dom, path, &stats, sizeof stats);
1314   CHECK_ERROR (r == -1, conn, "virDomainBlockStats");
1315
1316   rv = caml_alloc (5, 0);
1317   v = caml_copy_int64 (stats.rd_req); Store_field (rv, 0, v);
1318   v = caml_copy_int64 (stats.rd_bytes); Store_field (rv, 1, v);
1319   v = caml_copy_int64 (stats.wr_req); Store_field (rv, 2, v);
1320   v = caml_copy_int64 (stats.wr_bytes); Store_field (rv, 3, v);
1321   v = caml_copy_int64 (stats.errs); Store_field (rv, 4, v);
1322
1323   CAMLreturn (rv);
1324 #else
1325   NOT_SUPPORTED ("virDomainBlockStats");
1326 #endif
1327 }
1328
1329 CAMLprim value
1330 ocaml_libvirt_domain_interface_stats (value domv, value pathv)
1331 {
1332 #if HAVE_VIRDOMAININTERFACESTATS
1333   CAMLparam2 (domv, pathv);
1334   CAMLlocal2 (rv,v);
1335   virDomainPtr dom = Domain_val (domv);
1336   virConnectPtr conn = Connect_domv (domv);
1337   char *path = String_val (pathv);
1338   struct _virDomainInterfaceStats stats;
1339   int r;
1340
1341   WEAK_SYMBOL_CHECK (virDomainInterfaceStats);
1342   r = virDomainInterfaceStats (dom, path, &stats, sizeof stats);
1343   CHECK_ERROR (r == -1, conn, "virDomainInterfaceStats");
1344
1345   rv = caml_alloc (8, 0);
1346   v = caml_copy_int64 (stats.rx_bytes); Store_field (rv, 0, v);
1347   v = caml_copy_int64 (stats.rx_packets); Store_field (rv, 1, v);
1348   v = caml_copy_int64 (stats.rx_errs); Store_field (rv, 2, v);
1349   v = caml_copy_int64 (stats.rx_drop); Store_field (rv, 3, v);
1350   v = caml_copy_int64 (stats.tx_bytes); Store_field (rv, 4, v);
1351   v = caml_copy_int64 (stats.tx_packets); Store_field (rv, 5, v);
1352   v = caml_copy_int64 (stats.tx_errs); Store_field (rv, 6, v);
1353   v = caml_copy_int64 (stats.tx_drop); Store_field (rv, 7, v);
1354
1355   CAMLreturn (rv);
1356 #else
1357   NOT_SUPPORTED ("virDomainInterfaceStats");
1358 #endif
1359 }
1360
1361 CAMLprim value
1362 ocaml_libvirt_network_lookup_by_name (value connv, value namev)
1363 {
1364   CAMLparam2 (connv, namev);
1365   CAMLlocal1 (rv);
1366   virConnectPtr conn = Connect_val (connv);
1367   char *name = String_val (namev);
1368   virNetworkPtr r;
1369
1370   r = virNetworkLookupByName (conn, name);
1371   CHECK_ERROR (!r, conn, "virNetworkLookupByName");
1372
1373   rv = Val_network (r, connv);
1374   CAMLreturn (rv);
1375 }
1376
1377 CAMLprim value
1378 ocaml_libvirt_network_lookup_by_uuid (value connv, value uuidv)
1379 {
1380   CAMLparam2 (connv, uuidv);
1381   CAMLlocal1 (rv);
1382   virConnectPtr conn = Connect_val (connv);
1383   char *uuid = String_val (uuidv);
1384   virNetworkPtr r;
1385
1386   r = virNetworkLookupByUUID (conn, (unsigned char *) uuid);
1387   CHECK_ERROR (!r, conn, "virNetworkLookupByUUID");
1388
1389   rv = Val_network (r, connv);
1390   CAMLreturn (rv);
1391 }
1392
1393 CAMLprim value
1394 ocaml_libvirt_network_lookup_by_uuid_string (value connv, value uuidv)
1395 {
1396   CAMLparam2 (connv, uuidv);
1397   CAMLlocal1 (rv);
1398   virConnectPtr conn = Connect_val (connv);
1399   char *uuid = String_val (uuidv);
1400   virNetworkPtr r;
1401
1402   r = virNetworkLookupByUUIDString (conn, uuid);
1403   CHECK_ERROR (!r, conn, "virNetworkLookupByUUIDString");
1404
1405   rv = Val_network (r, connv);
1406   CAMLreturn (rv);
1407 }
1408
1409 CAMLprim value
1410 ocaml_libvirt_network_create_xml (value connv, value xmlv)
1411 {
1412   CAMLparam2 (connv, xmlv);
1413   CAMLlocal1 (rv);
1414   virConnectPtr conn = Connect_val (connv);
1415   char *xml = String_val (xmlv);
1416   virNetworkPtr r;
1417
1418   r = virNetworkCreateXML (conn, xml);
1419   CHECK_ERROR (!r, conn, "virNetworkCreateXML");
1420
1421   rv = Val_network (r, connv);
1422   CAMLreturn (rv);
1423 }
1424
1425 CAMLprim value
1426 ocaml_libvirt_network_define_xml (value connv, value xmlv)
1427 {
1428   CAMLparam2 (connv, xmlv);
1429   CAMLlocal1 (rv);
1430   virConnectPtr conn = Connect_val (connv);
1431   char *xml = String_val (xmlv);
1432   virNetworkPtr r;
1433
1434   r = virNetworkDefineXML (conn, xml);
1435   CHECK_ERROR (!r, conn, "virNetworkDefineXML");
1436
1437   rv = Val_network (r, connv);
1438   CAMLreturn (rv);
1439 }
1440
1441 CAMLprim value
1442 ocaml_libvirt_network_undefine (value netv)
1443 {
1444   CAMLparam1 (netv);
1445   virNetworkPtr net = Network_val (netv);
1446   virConnectPtr conn = Connect_netv (netv);
1447   int r;
1448
1449   r = virNetworkUndefine (net);
1450   CHECK_ERROR (r == -1, conn, "virNetworkUndefine");
1451
1452   CAMLreturn (Val_unit);
1453 }
1454
1455 CAMLprim value
1456 ocaml_libvirt_network_create (value netv)
1457 {
1458   CAMLparam1 (netv);
1459   virNetworkPtr net = Network_val (netv);
1460   virConnectPtr conn = Connect_netv (netv);
1461   int r;
1462
1463   r = virNetworkCreate (net);
1464   CHECK_ERROR (r == -1, conn, "virNetworkCreate");
1465
1466   CAMLreturn (Val_unit);
1467 }
1468
1469 CAMLprim value
1470 ocaml_libvirt_network_destroy (value netv)
1471 {
1472   CAMLparam1 (netv);
1473   virNetworkPtr net = Network_val (netv);
1474   virConnectPtr conn = Connect_netv (netv);
1475   int r;
1476
1477   r = virNetworkDestroy (net);
1478   CHECK_ERROR (r == -1, conn, "virNetworkDestroy");
1479
1480   /* So that we don't double-free in the finalizer: */
1481   Network_val (netv) = NULL;
1482
1483   CAMLreturn (Val_unit);
1484 }
1485
1486 CAMLprim value
1487 ocaml_libvirt_network_free (value netv)
1488 {
1489   CAMLparam1 (netv);
1490   virNetworkPtr net = Network_val (netv);
1491   virConnectPtr conn = Connect_netv (netv);
1492   int r;
1493
1494   r = virNetworkFree (net);
1495   CHECK_ERROR (r == -1, conn, "virNetworkFree");
1496
1497   /* So that we don't double-free in the finalizer: */
1498   Network_val (netv) = NULL;
1499
1500   CAMLreturn (Val_unit);
1501 }
1502
1503 CAMLprim value
1504 ocaml_libvirt_network_get_name (value netv)
1505 {
1506   CAMLparam1 (netv);
1507   CAMLlocal1 (rv);
1508   virNetworkPtr net = Network_val (netv);
1509   virConnectPtr conn = Connect_netv (netv);
1510   const char *r;
1511
1512   r = virNetworkGetName (net);
1513   CHECK_ERROR (!r, conn, "virNetworkGetName");
1514
1515   rv = caml_copy_string (r);
1516   CAMLreturn (rv);
1517 }
1518
1519 CAMLprim value
1520 ocaml_libvirt_network_get_uuid (value netv)
1521 {
1522   CAMLparam1 (netv);
1523   CAMLlocal1 (rv);
1524   virNetworkPtr net = Network_val (netv);
1525   virConnectPtr conn = Connect_netv (netv);
1526   unsigned char uuid[VIR_UUID_BUFLEN];
1527   int r;
1528
1529   r = virNetworkGetUUID (net, uuid);
1530   CHECK_ERROR (r == -1, conn, "virNetworkGetUUID");
1531
1532   rv = caml_copy_string ((char *) uuid);
1533   CAMLreturn (rv);
1534 }
1535
1536 CAMLprim value
1537 ocaml_libvirt_network_get_uuid_string (value netv)
1538 {
1539   CAMLparam1 (netv);
1540   CAMLlocal1 (rv);
1541   virNetworkPtr net = Network_val (netv);
1542   virConnectPtr conn = Connect_netv (netv);
1543   char uuid[VIR_UUID_STRING_BUFLEN];
1544   int r;
1545
1546   r = virNetworkGetUUIDString (net, uuid);
1547   CHECK_ERROR (r == -1, conn, "virNetworkGetUUIDString");
1548
1549   rv = caml_copy_string (uuid);
1550   CAMLreturn (rv);
1551 }
1552
1553 CAMLprim value
1554 ocaml_libvirt_network_get_xml_desc (value netv)
1555 {
1556   CAMLparam1 (netv);
1557   CAMLlocal1 (rv);
1558   virNetworkPtr net = Network_val (netv);
1559   virConnectPtr conn = Connect_netv (netv);
1560   char *r;
1561
1562   r = virNetworkGetXMLDesc (net, 0);
1563   CHECK_ERROR (!r, conn, "virNetworkGetXMLDesc");
1564
1565   rv = caml_copy_string (r);
1566   free (r);
1567   CAMLreturn (rv);
1568 }
1569
1570 CAMLprim value
1571 ocaml_libvirt_network_get_bridge_name (value netv)
1572 {
1573   CAMLparam1 (netv);
1574   CAMLlocal1 (rv);
1575   virNetworkPtr net = Network_val (netv);
1576   virConnectPtr conn = Connect_netv (netv);
1577   char *r;
1578
1579   r = virNetworkGetBridgeName (net);
1580   CHECK_ERROR (!r, conn, "virNetworkGetBridgeName");
1581
1582   rv = caml_copy_string (r);
1583   free (r);
1584   CAMLreturn (rv);
1585 }
1586
1587 CAMLprim value
1588 ocaml_libvirt_network_get_autostart (value netv)
1589 {
1590   CAMLparam1 (netv);
1591   virNetworkPtr net = Network_val (netv);
1592   virConnectPtr conn = Connect_netv (netv);
1593   int r, autostart;
1594
1595   r = virNetworkGetAutostart (net, &autostart);
1596   CHECK_ERROR (r == -1, conn, "virNetworkGetAutostart");
1597
1598   CAMLreturn (autostart ? Val_true : Val_false);
1599 }
1600
1601 CAMLprim value
1602 ocaml_libvirt_network_set_autostart (value netv, value autostartv)
1603 {
1604   CAMLparam2 (netv, autostartv);
1605   virNetworkPtr net = Network_val (netv);
1606   virConnectPtr conn = Connect_netv (netv);
1607   int r, autostart = autostartv == Val_true ? 1 : 0;
1608
1609   r = virNetworkSetAutostart (net, autostart);
1610   CHECK_ERROR (r == -1, conn, "virNetworkSetAutostart");
1611
1612   CAMLreturn (Val_unit);
1613 }
1614
1615 /*----------------------------------------------------------------------*/
1616
1617 CAMLprim value
1618 ocaml_libvirt_virterror_get_last_error (value unitv)
1619 {
1620   CAMLparam1 (unitv);
1621   CAMLlocal1 (rv);
1622   virErrorPtr err = virGetLastError ();
1623
1624   rv = Val_opt (err, (Val_ptr_t) Val_virterror);
1625
1626   CAMLreturn (rv);
1627 }
1628
1629 CAMLprim value
1630 ocaml_libvirt_virterror_get_last_conn_error (value connv)
1631 {
1632   CAMLparam1 (connv);
1633   CAMLlocal1 (rv);
1634   virConnectPtr conn = Connect_val (connv);
1635
1636   rv = Val_opt (conn, (Val_ptr_t) Val_connect);
1637
1638   CAMLreturn (rv);
1639 }
1640
1641 CAMLprim value
1642 ocaml_libvirt_virterror_reset_last_error (value unitv)
1643 {
1644   CAMLparam1 (unitv);
1645   virResetLastError ();
1646   CAMLreturn (Val_unit);
1647 }
1648
1649 CAMLprim value
1650 ocaml_libvirt_virterror_reset_last_conn_error (value connv)
1651 {
1652   CAMLparam1 (connv);
1653   virConnectPtr conn = Connect_val (connv);
1654   virConnResetLastError (conn);
1655   CAMLreturn (Val_unit);
1656 }
1657
1658 /*----------------------------------------------------------------------*/
1659
1660 /* Initialise the library. */
1661 CAMLprim value
1662 ocaml_libvirt_init (value unit)
1663 {
1664   CAMLparam1 (unit);
1665   CAMLlocal1 (rv);
1666   int r;
1667
1668   r = virInitialize ();
1669   CHECK_ERROR (r == -1, NULL, "virInitialize");
1670
1671   CAMLreturn (Val_unit);
1672 }
1673
1674 /*----------------------------------------------------------------------*/
1675
1676 static char *
1677 Optstring_val (value strv)
1678 {
1679   if (strv == Val_int (0))      /* None */
1680     return NULL;
1681   else                          /* Some string */
1682     return String_val (Field (strv, 0));
1683 }
1684
1685 static value
1686 Val_opt (void *ptr, Val_ptr_t Val_ptr)
1687 {
1688   CAMLparam0 ();
1689   CAMLlocal2 (optv, ptrv);
1690
1691   if (ptr) {                    /* Some ptr */
1692     optv = caml_alloc (1, 0);
1693     ptrv = Val_ptr (ptr);
1694     Store_field (optv, 0, ptrv);
1695   } else                        /* None */
1696     optv = Val_int (0);
1697
1698   CAMLreturn (optv);
1699 }
1700
1701 #if 0
1702 static value
1703 option_default (value option, value deflt)
1704 {
1705   if (option == Val_int (0))    /* "None" */
1706     return deflt;
1707   else                          /* "Some 'a" */
1708     return Field (option, 0);
1709 }
1710 #endif
1711
1712 static value
1713 _raise_virterror (virConnectPtr conn, const char *fn)
1714 {
1715   CAMLparam0 ();
1716   CAMLlocal1 (rv);
1717   virErrorPtr errp;
1718   struct _virError err;
1719
1720   errp = conn ? virConnGetLastError (conn) : virGetLastError ();
1721
1722   if (!errp) {
1723     /* Fake a _virError structure. */
1724     memset (&err, 0, sizeof err);
1725     err.code = VIR_ERR_INTERNAL_ERROR;
1726     err.domain = VIR_FROM_NONE;
1727     err.level = VIR_ERR_ERROR;
1728     err.message = (char *) fn;
1729     errp = &err;
1730   }
1731
1732   rv = Val_virterror (errp);
1733   caml_raise_with_arg (*caml_named_value ("ocaml_libvirt_virterror"), rv);
1734
1735   /*NOTREACHED*/
1736   CAMLreturn (Val_unit);
1737 }
1738
1739 static value
1740 Val_virterror (virErrorPtr err)
1741 {
1742   CAMLparam0 ();
1743   CAMLlocal3 (rv, connv, optv);
1744
1745   rv = caml_alloc (12, 0);
1746   Store_field (rv, 0, Val_int (err->code));
1747   Store_field (rv, 1, Val_int (err->domain));
1748   Store_field (rv, 2,
1749                Val_opt (err->message, (Val_ptr_t) caml_copy_string));
1750   Store_field (rv, 3, Val_int (err->level));
1751
1752   /* conn, dom and net fields, all optional */
1753   if (err->conn) {
1754     connv = Val_connect_no_finalize (err->conn);
1755     optv = caml_alloc (1, 0);
1756     Store_field (optv, 0, connv);
1757     Store_field (rv, 4, optv);  /* Some conn */
1758
1759     if (err->dom) {
1760       optv = caml_alloc (1, 0);
1761       Store_field (optv, 0, Val_domain_no_finalize (err->dom, connv));
1762       Store_field (rv, 5, optv); /* Some (dom, conn) */
1763     }
1764     else
1765       Store_field (rv, 5, Val_int (0)); /* None */
1766     if (err->net) {
1767       optv = caml_alloc (1, 0);
1768       Store_field (optv, 0, Val_network_no_finalize (err->net, connv));
1769       Store_field (rv, 11, optv); /* Some (net, conn) */
1770     } else
1771       Store_field (rv, 11, Val_int (0)); /* None */
1772   } else {
1773     Store_field (rv, 4, Val_int (0)); /* None */
1774     Store_field (rv, 5, Val_int (0)); /* None */
1775     Store_field (rv, 11, Val_int (0)); /* None */
1776   }
1777
1778   Store_field (rv, 6,
1779                Val_opt (err->str1, (Val_ptr_t) caml_copy_string));
1780   Store_field (rv, 7,
1781                Val_opt (err->str2, (Val_ptr_t) caml_copy_string));
1782   Store_field (rv, 8,
1783                Val_opt (err->str3, (Val_ptr_t) caml_copy_string));
1784   Store_field (rv, 9, caml_copy_int32 (err->int1));
1785   Store_field (rv, 10, caml_copy_int32 (err->int2));
1786
1787   CAMLreturn (rv);
1788 }
1789
1790 static void conn_finalize (value);
1791 static void dom_finalize (value);
1792 static void net_finalize (value);
1793
1794 static struct custom_operations conn_custom_operations = {
1795   "conn_custom_operations",
1796   conn_finalize,
1797   custom_compare_default,
1798   custom_hash_default,
1799   custom_serialize_default,
1800   custom_deserialize_default
1801 };
1802
1803 static struct custom_operations dom_custom_operations = {
1804   "dom_custom_operations",
1805   dom_finalize,
1806   custom_compare_default,
1807   custom_hash_default,
1808   custom_serialize_default,
1809   custom_deserialize_default
1810
1811 };
1812
1813 static struct custom_operations net_custom_operations = {
1814   "net_custom_operations",
1815   net_finalize,
1816   custom_compare_default,
1817   custom_hash_default,
1818   custom_serialize_default,
1819   custom_deserialize_default
1820 };
1821
1822 static value
1823 Val_connect (virConnectPtr conn)
1824 {
1825   CAMLparam0 ();
1826   CAMLlocal1 (rv);
1827   rv = caml_alloc_custom (&conn_custom_operations,
1828                           sizeof (virConnectPtr), 0, 1);
1829   Connect_val (rv) = conn;
1830   CAMLreturn (rv);
1831 }
1832
1833 /* This wraps up the raw domain handle (Domain.dom). */
1834 static value
1835 Val_dom (virDomainPtr dom)
1836 {
1837   CAMLparam0 ();
1838   CAMLlocal1 (rv);
1839   rv = caml_alloc_custom (&dom_custom_operations,
1840                           sizeof (virDomainPtr), 0, 1);
1841   Dom_val (rv) = dom;
1842   CAMLreturn (rv);
1843 }
1844
1845 /* This wraps up the raw network handle (Network.net). */
1846 static value
1847 Val_net (virNetworkPtr net)
1848 {
1849   CAMLparam0 ();
1850   CAMLlocal1 (rv);
1851   rv = caml_alloc_custom (&net_custom_operations,
1852                           sizeof (virNetworkPtr), 0, 1);
1853   Net_val (rv) = net;
1854   CAMLreturn (rv);
1855 }
1856
1857 /* No-finalize versions of Val_connect, Val_dom, Val_net ONLY for use
1858  * by virterror wrappers.
1859  */
1860 static value
1861 Val_connect_no_finalize (virConnectPtr conn)
1862 {
1863   CAMLparam0 ();
1864   CAMLlocal1 (rv);
1865   rv = caml_alloc (1, Abstract_tag);
1866   Store_field (rv, 0, (value) conn);
1867   CAMLreturn (rv);
1868 }
1869
1870 static value
1871 Val_dom_no_finalize (virDomainPtr dom)
1872 {
1873   CAMLparam0 ();
1874   CAMLlocal1 (rv);
1875   rv = caml_alloc (1, Abstract_tag);
1876   Store_field (rv, 0, (value) dom);
1877   CAMLreturn (rv);
1878 }
1879
1880 static value
1881 Val_net_no_finalize (virNetworkPtr net)
1882 {
1883   CAMLparam0 ();
1884   CAMLlocal1 (rv);
1885   rv = caml_alloc (1, Abstract_tag);
1886   Store_field (rv, 0, (value) net);
1887   CAMLreturn (rv);
1888 }
1889
1890 /* This wraps up the (dom, conn) pair (Domain.t). */
1891 static value
1892 Val_domain (virDomainPtr dom, value connv)
1893 {
1894   CAMLparam1 (connv);
1895   CAMLlocal2 (rv, v);
1896
1897   rv = caml_alloc_tuple (2);
1898   v = Val_dom (dom);
1899   Store_field (rv, 0, v);
1900   Store_field (rv, 1, connv);
1901   CAMLreturn (rv);
1902 }
1903
1904 /* This wraps up the (net, conn) pair (Network.t). */
1905 static value
1906 Val_network (virNetworkPtr net, value connv)
1907 {
1908   CAMLparam1 (connv);
1909   CAMLlocal2 (rv, v);
1910
1911   rv = caml_alloc_tuple (2);
1912   v = Val_net (net);
1913   Store_field (rv, 0, v);
1914   Store_field (rv, 1, connv);
1915   CAMLreturn (rv);
1916 }
1917
1918 /* No-finalize versions of Val_domain, Val_network ONLY for use by
1919  * virterror wrappers.
1920  */
1921 static value
1922 Val_domain_no_finalize (virDomainPtr dom, value connv)
1923 {
1924   CAMLparam1 (connv);
1925   CAMLlocal2 (rv, v);
1926
1927   rv = caml_alloc_tuple (2);
1928   v = Val_dom_no_finalize (dom);
1929   Store_field (rv, 0, v);
1930   Store_field (rv, 1, connv);
1931   CAMLreturn (rv);
1932 }
1933
1934 static value
1935 Val_network_no_finalize (virNetworkPtr net, value connv)
1936 {
1937   CAMLparam1 (connv);
1938   CAMLlocal2 (rv, v);
1939
1940   rv = caml_alloc_tuple (2);
1941   v = Val_net_no_finalize (net);
1942   Store_field (rv, 0, v);
1943   Store_field (rv, 1, connv);
1944   CAMLreturn (rv);
1945 }
1946
1947 static void
1948 conn_finalize (value connv)
1949 {
1950   virConnectPtr conn = Connect_val (connv);
1951   if (conn) (void) virConnectClose (conn);
1952 }
1953
1954 static void
1955 dom_finalize (value domv)
1956 {
1957   virDomainPtr dom = Dom_val (domv);
1958   if (dom) (void) virDomainFree (dom);
1959 }
1960
1961 static void
1962 net_finalize (value netv)
1963 {
1964   virNetworkPtr net = Net_val (netv);
1965   if (net) (void) virNetworkFree (net);
1966 }