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