summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-11-09 17:47:07 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-11-09 19:50:57 +0000
commita3b6751863b4e7e620dd1b75b4a8d8187d2069a5 (patch)
treee217f7c6b152612453fb0054f16112a610180e77
parent2013e005bd02f5706887c8861f10410ffd82084f (diff)
downloadlibguestfs-a3b6751863b4e7e620dd1b75b4a8d8187d2069a5.tar.gz
libguestfs-a3b6751863b4e7e620dd1b75b4a8d8187d2069a5.tar.xz
libguestfs-a3b6751863b4e7e620dd1b75b4a8d8187d2069a5.zip
lib: Add new C API calls: guestfs_push_error_handler,
guestfs_pop_error_handler. The addition of these calls makes it much simpler to temporarily disable or ignore errors: guestfs_push_error_handler (g, NULL, NULL); guestfs_mkdir (g, "/foo"); /* We don't care if this fails. */ guestfs_pop_error_handler (g); Note these calls are used by the C API only. They are not necessary in other languages, because those map errors to exceptions. The subsequent commits change existing code to use push/pop instead of laboriously saving and restoring the error handler.
-rw-r--r--generator/c.ml6
-rw-r--r--src/guestfs-internal.h14
-rw-r--r--src/guestfs.c60
-rw-r--r--src/guestfs.pod26
4 files changed, 95 insertions, 11 deletions
diff --git a/generator/c.ml b/generator/c.ml
index b8c601be..1b99e519 100644
--- a/generator/c.ml
+++ b/generator/c.ml
@@ -449,6 +449,10 @@ typedef void (*guestfs_abort_cb) (void) __attribute__((__noreturn__));
extern GUESTFS_DLL_PUBLIC void guestfs_set_error_handler (guestfs_h *g, guestfs_error_handler_cb cb, void *opaque);
extern GUESTFS_DLL_PUBLIC guestfs_error_handler_cb guestfs_get_error_handler (guestfs_h *g, void **opaque_rtn);
+#define LIBGUESTFS_HAVE_PUSH_ERROR_HANDLER 1
+extern GUESTFS_DLL_PUBLIC void guestfs_push_error_handler (guestfs_h *g, guestfs_error_handler_cb cb, void *opaque);
+#define LIBGUESTFS_HAVE_POP_ERROR_HANDLER 1
+extern GUESTFS_DLL_PUBLIC void guestfs_pop_error_handler (guestfs_h *g);
extern GUESTFS_DLL_PUBLIC void guestfs_set_out_of_memory_handler (guestfs_h *g, guestfs_abort_cb);
extern GUESTFS_DLL_PUBLIC guestfs_abort_cb guestfs_get_out_of_memory_handler (guestfs_h *g);
@@ -1566,6 +1570,8 @@ and generate_linker_script () =
"guestfs_last_errno";
"guestfs_last_error";
"guestfs_next_private";
+ "guestfs_pop_error_handler";
+ "guestfs_push_error_handler";
"guestfs_set_close_callback";
"guestfs_set_error_handler";
"guestfs_set_event_callback";
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index 17903d30..4a12de76 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -180,6 +180,13 @@ extern struct attach_ops attach_ops_appliance;
extern struct attach_ops attach_ops_libvirt;
extern struct attach_ops attach_ops_unix;
+/* Stack of old error handlers. */
+struct error_cb_stack {
+ struct error_cb_stack *next;
+ guestfs_error_handler_cb error_cb;
+ void * error_cb_data;
+};
+
struct guestfs_h
{
struct guestfs_h *next; /* Linked list of open handles. */
@@ -248,10 +255,13 @@ struct guestfs_h
char *int_tmpdir; /* $LIBGUESTFS_TMPDIR or guestfs_set_tmpdir or NULL */
char *int_cachedir; /* $LIBGUESTFS_CACHEDIR or guestfs_set_cachedir or NULL */
- /* Callbacks. */
- guestfs_abort_cb abort_cb;
+ /* Error handler, plus stack of old error handlers. */
guestfs_error_handler_cb error_cb;
void * error_cb_data;
+ struct error_cb_stack *error_cb_stack;
+
+ /* Out of memory error handler. */
+ guestfs_abort_cb abort_cb;
/* Events. */
struct event *events;
diff --git a/src/guestfs.c b/src/guestfs.c
index 5b969185..6b21e390 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -62,7 +62,7 @@
#include "guestfs_protocol.h"
static int parse_attach_method (guestfs_h *g, const char *method);
-static void default_error_cb (guestfs_h *g, void *data, const char *msg);
+static void init_error_handler (guestfs_h *g);
static int shutdown_backend (guestfs_h *g, int check_for_errors);
static void close_handles (void);
@@ -117,9 +117,8 @@ guestfs_create_flags (unsigned flags, ...)
g->fd[1] = -1;
g->sock = -1;
+ init_error_handler (g);
g->abort_cb = abort;
- g->error_cb = default_error_cb;
- g->error_cb_data = NULL;
g->recovery_proc = 1;
g->autosync = 1;
@@ -340,6 +339,9 @@ guestfs_close (guestfs_h *g)
free (qp);
}
+ while (g->error_cb_stack)
+ guestfs_pop_error_handler (g);
+
if (g->pda)
hash_free (g->pda);
free (g->tmpdir);
@@ -500,12 +502,6 @@ guestfs___trace (guestfs_h *g, const char *fs, ...)
free (msg);
}
-static void
-default_error_cb (guestfs_h *g, void *data, const char *msg)
-{
- fprintf (stderr, _("libguestfs: error: %s\n"), msg);
-}
-
void
guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...)
{
@@ -681,6 +677,52 @@ guestfs_get_error_handler (guestfs_h *g, void **data_rtn)
}
void
+guestfs_push_error_handler (guestfs_h *g,
+ guestfs_error_handler_cb cb, void *data)
+{
+ struct error_cb_stack *old_stack;
+
+ old_stack = g->error_cb_stack;
+ g->error_cb_stack = safe_malloc (g, sizeof (struct error_cb_stack));
+ g->error_cb_stack->next = old_stack;
+ g->error_cb_stack->error_cb = g->error_cb;
+ g->error_cb_stack->error_cb_data = g->error_cb_data;
+
+ guestfs_set_error_handler (g, cb, data);
+}
+
+void
+guestfs_pop_error_handler (guestfs_h *g)
+{
+ struct error_cb_stack *next_stack;
+
+ if (g->error_cb_stack) {
+ next_stack = g->error_cb_stack->next;
+ guestfs_set_error_handler (g, g->error_cb_stack->error_cb,
+ g->error_cb_stack->error_cb_data);
+ free (g->error_cb_stack);
+ g->error_cb_stack = next_stack;
+ }
+ else
+ init_error_handler (g);
+}
+
+static void default_error_cb (guestfs_h *g, void *data, const char *msg);
+
+static void
+init_error_handler (guestfs_h *g)
+{
+ g->error_cb = default_error_cb;
+ g->error_cb_data = NULL;
+}
+
+static void
+default_error_cb (guestfs_h *g, void *data, const char *msg)
+{
+ fprintf (stderr, _("libguestfs: error: %s\n"), msg);
+}
+
+void
guestfs_user_cancel (guestfs_h *g)
{
g->user_cancel = 1;
diff --git a/src/guestfs.pod b/src/guestfs.pod
index bac81d86..e0246619 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -1904,6 +1904,32 @@ If you set C<cb> to C<NULL> then I<no> handler is called.
Returns the current error handler callback.
+=head2 guestfs_push_error_handler
+
+ void guestfs_push_error_handler (guestfs_h *g,
+ guestfs_error_handler_cb cb,
+ void *opaque);
+
+This is the same as L</guestfs_set_error_handler>, except that the old
+error handler is stashed away in a stack inside the handle. You can
+restore the previous error handler by calling
+L</guestfs_pop_error_handler>.
+
+Use the following code to temporarily disable errors around a function:
+
+ guestfs_push_error_handler (g, NULL, NULL);
+ guestfs_mkdir (g, "/foo"); /* We don't care if this fails. */
+ guestfs_pop_error_handler (g);
+
+=head2 guestfs_pop_error_handler
+
+ void guestfs_pop_error_handler (guestfs_h *g);
+
+Restore the previous error handler (see L</guestfs_push_error_handler>).
+
+If you pop the stack too many times, then the default error handler is
+restored.
+
=head2 guestfs_set_out_of_memory_handler
typedef void (*guestfs_abort_cb) (void);