-static char *Optstring_val (value strv);
-typedef value (*Val_ptr_t) (void *);
-static value Val_opt (void *ptr, Val_ptr_t Val_ptr);
-/*static value option_default (value option, value deflt);*/
-static value _raise_virterror (virConnectPtr conn, const char *fn);
-static value Val_virterror (virErrorPtr err);
-
-#define CHECK_ERROR(cond, conn, fn) \
- do { if (cond) _raise_virterror (conn, fn); } while (0)
-
-#define NOT_SUPPORTED(fn) \
- caml_invalid_argument (fn " not supported")
-
-/* For more about weak symbols, see:
- * http://kolpackov.net/pipermail/notes/2004-March/000006.html
- * We are using this to do runtime detection of library functions
- * so that if we dynamically link with an older version of
- * libvirt than we were compiled against, it won't fail (provided
- * libvirt >= 0.2.1 - we don't support anything older).
- */
-#ifdef __GNUC__
-#ifdef linux
-#if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
-#define HAVE_WEAK_SYMBOLS 1
-#endif
-#endif
-#endif
-
-#ifdef HAVE_WEAK_SYMBOLS
-#define WEAK_SYMBOL_CHECK(sym) \
- do { if (!sym) NOT_SUPPORTED(#sym); } while (0)
-#else
-#define WEAK_SYMBOL_CHECK(sym)
-#endif /* HAVE_WEAK_SYMBOLS */
-
-#ifdef HAVE_WEAK_SYMBOLS
-#ifdef HAVE_VIRCONNECTGETHOSTNAME
-extern char *virConnectGetHostname (virConnectPtr conn)
- __attribute__((weak));
-#endif
-#ifdef HAVE_VIRCONNECTGETURI
-extern char *virConnectGetURI (virConnectPtr conn)
- __attribute__((weak));
-#endif
-#ifdef HAVE_VIRDOMAINBLOCKSTATS
-extern int virDomainBlockStats (virDomainPtr dom,
- const char *path,
- virDomainBlockStatsPtr stats,
- size_t size)
- __attribute__((weak));
-#endif
-#ifdef HAVE_VIRDOMAINGETSCHEDULERPARAMETERS
-extern int virDomainGetSchedulerParameters (virDomainPtr domain,
- virSchedParameterPtr params,
- int *nparams)
- __attribute__((weak));
-#endif
-#ifdef HAVE_VIRDOMAINGETSCHEDULERTYPE
-extern char *virDomainGetSchedulerType(virDomainPtr domain,
- int *nparams)
- __attribute__((weak));
-#endif
-#ifdef HAVE_VIRDOMAININTERFACESTATS
-extern int virDomainInterfaceStats (virDomainPtr dom,
- const char *path,
- virDomainInterfaceStatsPtr stats,
- size_t size)
- __attribute__((weak));
-#endif
-#ifdef HAVE_VIRDOMAINMIGRATE
-extern virDomainPtr virDomainMigrate (virDomainPtr domain, virConnectPtr dconn,
- unsigned long flags, const char *dname,
- const char *uri, unsigned long bandwidth)
- __attribute__((weak));
-#endif
-#ifdef HAVE_VIRDOMAINSETSCHEDULERPARAMETERS
-extern int virDomainSetSchedulerParameters (virDomainPtr domain,
- virSchedParameterPtr params,
- int nparams)
- __attribute__((weak));
-#endif
-#endif /* HAVE_WEAK_SYMBOLS */
-
-/*----------------------------------------------------------------------*/
-
-CAMLprim value
-ocaml_libvirt_get_version (value driverv, value unit)
-{
- CAMLparam2 (driverv, unit);
- CAMLlocal1 (rv);
- const char *driver = Optstring_val (driverv);
- unsigned long libVer, typeVer = 0, *typeVer_ptr;
- int r;
-
- typeVer_ptr = driver ? &typeVer : NULL;
- r = virGetVersion (&libVer, driver, typeVer_ptr);
- CHECK_ERROR (r == -1, NULL, "virGetVersion");
-
- rv = caml_alloc_tuple (2);
- Store_field (rv, 0, Val_int (libVer));
- Store_field (rv, 1, Val_int (typeVer));
- CAMLreturn (rv);
-}
-
-/*----------------------------------------------------------------------*/
-
-/* Some notes about the use of custom blocks to store virConnectPtr,
- * virDomainPtr and virNetworkPtr.
- *------------------------------------------------------------------
- *
- * Libvirt does some tricky reference counting to keep track of
- * virConnectPtr's, virDomainPtr's and virNetworkPtr's.
- *
- * There is only one function which can return a virConnectPtr
- * (virConnectOpen*) and that allocates a new one each time.
- *
- * virDomainPtr/virNetworkPtr's on the other hand can be returned
- * repeatedly (for the same underlying domain/network), and we must
- * keep track of each one and explicitly free it with virDomainFree
- * or virNetworkFree. If we lose track of one then the reference
- * counting in libvirt will keep it open. We therefore wrap these
- * in a custom block with a finalizer function.
- *
- * We also have to allow the user to explicitly free them, in
- * which case we set the pointer inside the custom block to NULL.
- * The finalizer notices this and doesn't free the object.
- *
- * Domains and networks "belong to" a connection. We have to avoid
- * the situation like this:
- *
- * let conn = Connect.open ... in
- * let dom = Domain.lookup_by_id conn 0 in
- * (* conn goes out of scope and is garbage collected *)
- * printf "dom name = %s\n" (Domain.get_name dom)
- *
- * The reason is that when conn is garbage collected, virConnectClose
- * is called and any subsequent operations on dom will fail (in fact
- * will probably segfault). To stop this from happening, the OCaml
- * wrappers store domains (and networks) as explicit (dom, conn)
- * pairs.
- *
- * Further complication with virterror / exceptions: Virterror gives
- * us virConnectPtr, virDomainPtr, virNetworkPtr pointers. If we
- * follow standard practice and wrap these up in blocks with
- * finalizers then we'll end up double-freeing (in particular, calling
- * virConnectClose at the wrong time). So for virterror, we have
- * "special" wrapper functions (Val_connect_no_finalize, etc.).
- */
-
-/* Unwrap a custom block. */
-#define Connect_val(rv) (*((virConnectPtr *)Data_custom_val(rv)))
-#define Dom_val(rv) (*((virDomainPtr *)Data_custom_val(rv)))
-#define Net_val(rv) (*((virNetworkPtr *)Data_custom_val(rv)))
-
-/* Wrap up a pointer to something in a custom block. */
-static value Val_connect (virConnectPtr conn);
-static value Val_dom (virDomainPtr dom);
-static value Val_net (virNetworkPtr net);
-
-/* ONLY for use by virterror wrappers. */
-static value Val_connect_no_finalize (virConnectPtr conn);
-static value Val_dom_no_finalize (virDomainPtr dom);
-static value Val_net_no_finalize (virNetworkPtr net);
-
-/* Domains and networks are stored as pairs (dom/net, conn), so have
- * some convenience functions for unwrapping and wrapping them.
- */
-#define Domain_val(rv) (Dom_val(Field((rv),0)))
-#define Network_val(rv) (Net_val(Field((rv),0)))
-#define Connect_domv(rv) (Connect_val(Field((rv),1)))
-#define Connect_netv(rv) (Connect_val(Field((rv),1)))
-
-static value Val_domain (virDomainPtr dom, value connv);
-static value Val_network (virNetworkPtr net, value connv);
-
-/* ONLY for use by virterror wrappers. */
-static value Val_domain_no_finalize (virDomainPtr dom, value connv);
-static value Val_network_no_finalize (virNetworkPtr net, value connv);
-
-/*----------------------------------------------------------------------*/
-
-/* Connection object. */
-
-CAMLprim value
-ocaml_libvirt_connect_open (value namev, value unit)
-{
- CAMLparam2 (namev, unit);
- CAMLlocal1 (rv);
- const char *name = Optstring_val (namev);
- virConnectPtr conn;
-
- conn = virConnectOpen (name);
- CHECK_ERROR (!conn, NULL, "virConnectOpen");
-
- rv = Val_connect (conn);
-
- CAMLreturn (rv);
-}
-
-CAMLprim value
-ocaml_libvirt_connect_open_readonly (value namev, value unit)
-{
- CAMLparam2 (namev, unit);
- CAMLlocal1 (rv);
- const char *name = Optstring_val (namev);
- virConnectPtr conn;
-
- conn = virConnectOpenReadOnly (name);
- CHECK_ERROR (!conn, NULL, "virConnectOpen");
-
- rv = Val_connect (conn);