From a3b6751863b4e7e620dd1b75b4a8d8187d2069a5 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 9 Nov 2012 17:47:07 +0100 Subject: 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. --- src/guestfs-internal.h | 14 ++++++++++-- src/guestfs.c | 60 ++++++++++++++++++++++++++++++++++++++++++-------- src/guestfs.pod | 26 ++++++++++++++++++++++ 3 files changed, 89 insertions(+), 11 deletions(-) (limited to 'src') 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, ...) { @@ -680,6 +676,52 @@ guestfs_get_error_handler (guestfs_h *g, void **data_rtn) return g->error_cb; } +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) { 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 to C then I 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, 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. + +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). + +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); -- cgit