2 * Copyright (C) 2009-2010 Red Hat Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <caml/config.h>
27 #include <caml/alloc.h>
28 #include <caml/callback.h>
29 #include <caml/custom.h>
30 #include <caml/fail.h>
31 #include <caml/memory.h>
32 #include <caml/mlvalues.h>
33 #include <caml/printexc.h>
34 #include <caml/signals.h>
36 #include "guestfs_c.h"
38 static void clear_progress_callback (guestfs_h *g);
39 static void progress_callback (guestfs_h *g, void *data, int proc_nr, int serial, uint64_t position, uint64_t total);
41 /* This macro was added in OCaml 3.10. Backport for earlier versions. */
43 #define CAMLreturnT(type, result) do{ \
44 type caml__temp_result = (result); \
45 caml_local_roots = caml__frame; \
46 return (caml__temp_result); \
50 /* These prototypes are solely to quiet gcc warning. */
51 CAMLprim value ocaml_guestfs_create (void);
52 CAMLprim value ocaml_guestfs_close (value gv);
53 CAMLprim value ocaml_guestfs_set_progress_callback (value gv, value closure);
54 CAMLprim value ocaml_guestfs_clear_progress_callback (value gv);
56 /* Allocate handles and deal with finalization. */
58 guestfs_finalize (value gv)
60 guestfs_h *g = Guestfs_val (gv);
62 clear_progress_callback (g);
67 static struct custom_operations guestfs_custom_operations = {
68 (char *) "guestfs_custom_operations",
70 custom_compare_default,
72 custom_serialize_default,
73 custom_deserialize_default
77 Val_guestfs (guestfs_h *g)
82 rv = caml_alloc_custom (&guestfs_custom_operations,
83 sizeof (guestfs_h *), 0, 1);
90 ocaml_guestfs_raise_error (guestfs_h *g, const char *func)
96 msg = guestfs_last_error (g);
99 v = caml_copy_string (msg);
101 v = caml_copy_string (func);
102 caml_raise_with_arg (*caml_named_value ("ocaml_guestfs_error"), v);
107 ocaml_guestfs_raise_closed (const char *func)
112 v = caml_copy_string (func);
113 caml_raise_with_arg (*caml_named_value ("ocaml_guestfs_closed"), v);
119 ocaml_guestfs_create (void)
125 g = guestfs_create ();
127 caml_failwith ("failed to create guestfs handle");
129 guestfs_set_error_handler (g, NULL, NULL);
131 gv = Val_guestfs (g);
137 ocaml_guestfs_close (value gv)
141 guestfs_finalize (gv);
143 /* So we don't double-free in the finalizer. */
144 Guestfs_val (gv) = NULL;
146 CAMLreturn (Val_unit);
149 /* Copy string array value. */
151 ocaml_guestfs_strings_val (guestfs_h *g, value sv)
157 r = guestfs_safe_malloc (g, sizeof (char *) * (Wosize_val (sv) + 1));
158 for (i = 0; i < Wosize_val (sv); ++i)
159 r[i] = guestfs_safe_strdup (g, String_val (Field (sv, i)));
162 CAMLreturnT (char **, r);
165 /* Free array of strings. */
167 ocaml_guestfs_free_strings (char **argv)
171 for (i = 0; argv[i] != NULL; ++i)
176 #define PROGRESS_ROOT_KEY "_ocaml_progress_root"
178 /* Guestfs.set_progress_callback */
180 ocaml_guestfs_set_progress_callback (value gv, value closure)
182 CAMLparam2 (gv, closure);
184 guestfs_h *g = Guestfs_val (gv);
185 clear_progress_callback (g);
187 value *root = guestfs_safe_malloc (g, sizeof *root);
190 /* XXX This global root is generational, but we cannot rely on every
191 * user having the OCaml 3.11 version which supports this.
193 caml_register_global_root (root);
195 guestfs_set_private (g, PROGRESS_ROOT_KEY, root);
197 guestfs_set_progress_callback (g, progress_callback, root);
199 CAMLreturn (Val_unit);
202 /* Guestfs.clear_progress_callback */
204 ocaml_guestfs_clear_progress_callback (value gv)
208 guestfs_h *g = Guestfs_val (gv);
209 clear_progress_callback (g);
211 CAMLreturn (Val_unit);
215 clear_progress_callback (guestfs_h *g)
217 guestfs_set_progress_callback (g, NULL, NULL);
219 value *root = guestfs_get_private (g, PROGRESS_ROOT_KEY);
221 caml_remove_global_root (root);
223 guestfs_set_private (g, PROGRESS_ROOT_KEY, NULL);
228 progress_callback_locked (guestfs_h *g ATTRIBUTE_UNUSED, void *root,
229 int proc_nr, int serial, uint64_t position, uint64_t total)
232 CAMLlocal5 (proc_nrv, serialv, positionv, totalv, rv);
234 proc_nrv = Val_int (proc_nr);
235 serialv = Val_int (serial);
236 positionv = caml_copy_int64 (position);
237 totalv = caml_copy_int64 (total);
239 value args[4] = { proc_nrv, serialv, positionv, totalv };
241 rv = caml_callbackN_exn (*(value*)root, 4, args);
243 /* Callbacks shouldn't throw exceptions. There's not much we can do
244 * except to print it.
246 if (Is_exception_result (rv))
247 fprintf (stderr, "libguestfs: uncaught OCaml exception in progress callback: %s",
248 caml_format_exception (Extract_exception (rv)));
254 progress_callback (guestfs_h *g ATTRIBUTE_UNUSED, void *root,
255 int proc_nr, int serial, uint64_t position, uint64_t total)
257 /* Ensure we are holding the GC lock before any GC operations are
258 * possible. (RHBZ#725824)
260 caml_leave_blocking_section ();
262 progress_callback_locked (g, root, proc_nr, serial, position, total);
264 caml_enter_blocking_section ();