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