1 /* OCaml bindings for libvirt.
2 * (C) Copyright 2007 Richard W.M. Jones, Red Hat Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /* Please read libvirt/README file. */
22 static char *Optstring_val (value strv);
23 typedef value (*Val_ptr_t) (void *);
24 static value Val_opt (void *ptr, Val_ptr_t Val_ptr);
25 /*static value option_default (value option, value deflt);*/
26 static void _raise_virterror (virConnectPtr conn, const char *fn) Noreturn;
27 static void not_supported (const char *fn) Noreturn;
28 static value Val_virterror (virErrorPtr err);
30 /* Use this around synchronous libvirt API calls to release the OCaml
31 * lock, allowing other threads to run simultaneously. 'code' must not
32 * perform any caml_* calls, run any OCaml code, or raise any exception.
33 * http://web.archive.org/web/20030521020915/http://caml.inria.fr/archives/200106/msg00199.html
35 #define NONBLOCKING(code) \
37 caml_enter_blocking_section (); \
39 caml_leave_blocking_section (); \
42 /* Check error condition from a libvirt function, and automatically raise
43 * an exception if one is found.
45 #define CHECK_ERROR(cond, conn, fn) \
46 do { if (cond) _raise_virterror (conn, fn); } while (0)
48 /* For more about weak symbols, see:
49 * http://kolpackov.net/pipermail/notes/2004-March/000006.html
50 * We are using this to do runtime detection of library functions
51 * so that if we dynamically link with an older version of
52 * libvirt than we were compiled against, it won't fail (provided
53 * libvirt >= 0.2.1 - we don't support anything older).
57 #if (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || (__GNUC__ > 3)
58 #define HAVE_WEAK_SYMBOLS 1
63 #ifdef HAVE_WEAK_SYMBOLS
64 #define WEAK_SYMBOL_CHECK(sym) \
65 do { if (!sym) not_supported(#sym); } while (0)
67 #define WEAK_SYMBOL_CHECK(sym)
68 #endif /* HAVE_WEAK_SYMBOLS */
70 /*----------------------------------------------------------------------*/
72 /* Some notes about the use of custom blocks to store virConnectPtr,
73 * virDomainPtr and virNetworkPtr.
74 *------------------------------------------------------------------
76 * Libvirt does some tricky reference counting to keep track of
77 * virConnectPtr's, virDomainPtr's and virNetworkPtr's.
79 * There is only one function which can return a virConnectPtr
80 * (virConnectOpen*) and that allocates a new one each time.
82 * virDomainPtr/virNetworkPtr's on the other hand can be returned
83 * repeatedly (for the same underlying domain/network), and we must
84 * keep track of each one and explicitly free it with virDomainFree
85 * or virNetworkFree. If we lose track of one then the reference
86 * counting in libvirt will keep it open. We therefore wrap these
87 * in a custom block with a finalizer function.
89 * We also have to allow the user to explicitly free them, in
90 * which case we set the pointer inside the custom block to NULL.
91 * The finalizer notices this and doesn't free the object.
93 * Domains and networks "belong to" a connection. We have to avoid
94 * the situation like this:
96 * let conn = Connect.open ... in
97 * let dom = Domain.lookup_by_id conn 0 in
98 * (* conn goes out of scope and is garbage collected *)
99 * printf "dom name = %s\n" (Domain.get_name dom)
101 * The reason is that when conn is garbage collected, virConnectClose
102 * is called and any subsequent operations on dom will fail (in fact
103 * will probably segfault). To stop this from happening, the OCaml
104 * wrappers store domains (and networks) as explicit (dom, conn)
107 * Further complication with virterror / exceptions: Virterror gives
108 * us virConnectPtr, virDomainPtr, virNetworkPtr pointers. If we
109 * follow standard practice and wrap these up in blocks with
110 * finalizers then we'll end up double-freeing (in particular, calling
111 * virConnectClose at the wrong time). So for virterror, we have
112 * "special" wrapper functions (Val_connect_no_finalize, etc.).
114 * Update 2008/01: Storage pools and volumes work the same way as
115 * domains and networks. And jobs.
118 /* Unwrap a custom block. */
119 #define Connect_val(rv) (*((virConnectPtr *)Data_custom_val(rv)))
120 #define Dom_val(rv) (*((virDomainPtr *)Data_custom_val(rv)))
121 #define Net_val(rv) (*((virNetworkPtr *)Data_custom_val(rv)))
122 #ifdef HAVE_VIRSTORAGEPOOLPTR
123 #define Pol_val(rv) (*((virStoragePoolPtr *)Data_custom_val(rv)))
125 #ifdef HAVE_VIRSTORAGEVOLPTR
126 #define Vol_val(rv) (*((virStorageVolPtr *)Data_custom_val(rv)))
128 #ifdef HAVE_VIRJOBPTR
129 #define Jb_val(rv) (*((virJobPtr *)Data_custom_val(rv)))
132 /* Wrap up a pointer to something in a custom block. */
133 static value Val_connect (virConnectPtr conn);
134 static value Val_dom (virDomainPtr dom);
135 static value Val_net (virNetworkPtr net);
136 #ifdef HAVE_VIRSTORAGEPOOLPTR
137 static value Val_pol (virStoragePoolPtr pool);
139 #ifdef HAVE_VIRSTORAGEVOLPTR
140 static value Val_vol (virStorageVolPtr vol);
142 #ifdef HAVE_VIRJOBPTR
143 static value Val_jb (virJobPtr jb);
146 /* ONLY for use by virterror wrappers. */
147 static value Val_connect_no_finalize (virConnectPtr conn);
148 static value Val_dom_no_finalize (virDomainPtr dom);
149 static value Val_net_no_finalize (virNetworkPtr net);
151 /* Domains and networks are stored as pairs (dom/net, conn), so have
152 * some convenience functions for unwrapping and wrapping them.
154 #define Domain_val(rv) (Dom_val(Field((rv),0)))
155 #define Network_val(rv) (Net_val(Field((rv),0)))
156 #ifdef HAVE_VIRSTORAGEPOOLPTR
157 #define Pool_val(rv) (Pol_val(Field((rv),0)))
159 #ifdef HAVE_VIRSTORAGEVOLPTR
160 #define Volume_val(rv) (Vol_val(Field((rv),0)))
162 #ifdef HAVE_VIRJOBPTR
163 #define Job_val(rv) (Jb_val(Field((rv),0)))
165 #define Connect_domv(rv) (Connect_val(Field((rv),1)))
166 #define Connect_netv(rv) (Connect_val(Field((rv),1)))
167 #ifdef HAVE_VIRSTORAGEPOOLPTR
168 #define Connect_polv(rv) (Connect_val(Field((rv),1)))
170 #ifdef HAVE_VIRSTORAGEVOLPTR
171 #define Connect_volv(rv) (Connect_val(Field((rv),1)))
173 #ifdef HAVE_VIRJOBPTR
174 #define Connect_jobv(rv) (Connect_val(Field((rv),1)))
177 static value Val_domain (virDomainPtr dom, value connv);
178 static value Val_network (virNetworkPtr net, value connv);
179 #ifdef HAVE_VIRSTORAGEPOOLPTR
180 static value Val_pool (virStoragePoolPtr pol, value connv);
182 #ifdef HAVE_VIRSTORAGEVOLPTR
183 static value Val_volume (virStorageVolPtr vol, value connv);
185 #ifdef HAVE_VIRJOBPTR
186 static value Val_job (virJobPtr jb, value connv);
189 /* ONLY for use by virterror wrappers. */
190 static value Val_domain_no_finalize (virDomainPtr dom, value connv);
191 static value Val_network_no_finalize (virNetworkPtr net, value connv);