| /* |
| libparted - a library for manipulating disk partitions |
| Copyright (C) 1999, 2000, 2007 Free Software Foundation, Inc. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| /** \file exception.c */ |
| |
| /** |
| * \addtogroup PedException |
| * |
| * \brief Exception handling. |
| * |
| * There are a few types of exceptions: PED_EXCEPTION_INFORMATION, |
| * PED_EXCEPTION_WARNING, PED_EXCEPTION_ERROR, PED_EXCEPTION_FATAL, |
| * PED_EXCEPTION_BUG. |
| * |
| * They are "thrown" when one of the above events occur while executing |
| * a libparted function. For example, if ped_device_open() fails |
| * because the device doesn't exist, an exception will be thrown. |
| * Exceptions contain text describing what the event was. It will give |
| * at least one option for resolving the exception: PED_EXCEPTION_FIX, |
| * PED_EXCEPTION_YES, PED_EXCEPTION_NO, PED_EXCEPTION_OK, PED_EXCEPTION_RETRY, |
| * PED_EXCEPTION_IGNORE, PED_EXCEPTION_CANCEL. After an exception is thrown, |
| * there are two things that can happen: |
| * |
| * -# an exception handler is called, which selects how the exception should be |
| * resolved (usually by asking the user). Also note: an exception handler may |
| * choose to return PED_EXCEPTION_UNHANDLED. In this case, a default action |
| * will be taken by libparted (respectively the code that threw the |
| * exception). In general, a default action will be "safe". |
| * -# the exception is not handled, because the caller of the function wants to |
| * handle everything itself. In this case, PED_EXCEPTION_UNHANDLED is |
| * returned. |
| * |
| * @{ |
| */ |
| |
| #include <config.h> |
| |
| #include <parted/parted.h> |
| #include <parted/debug.h> |
| |
| #define N_(String) String |
| #if ENABLE_NLS |
| # include <libintl.h> |
| # define _(String) dgettext (PACKAGE, String) |
| #else |
| # define _(String) (String) |
| #endif /* ENABLE_NLS */ |
| |
| #include <stdio.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| |
| int ped_exception = 0; |
| |
| static PedExceptionOption default_handler (PedException* ex); |
| |
| static PedExceptionHandler* ex_handler = default_handler; |
| static PedException* ex = NULL; |
| static int ex_fetch_count = 0; |
| |
| static char* type_strings [] = { |
| N_("Information"), |
| N_("Warning"), |
| N_("Error"), |
| N_("Fatal"), |
| N_("Bug"), |
| N_("No Implementation") |
| }; |
| |
| static char* option_strings [] = { |
| N_("Fix"), |
| N_("Yes"), |
| N_("No"), |
| N_("OK"), |
| N_("Retry"), |
| N_("Ignore"), |
| N_("Cancel") |
| }; |
| |
| /** |
| * Return a string describing an exception type. |
| */ |
| char* |
| ped_exception_get_type_string (PedExceptionType ex_type) |
| { |
| return type_strings [ex_type - 1]; |
| } |
| |
| /* FIXME: move this out to the prospective math.c */ |
| /* FIXME: this can probably be done more efficiently */ |
| static int |
| ped_log2 (int n) |
| { |
| int x; |
| |
| PED_ASSERT (n > 0, return -1); |
| |
| for (x=0; 1 << x <= n; x++); |
| |
| return x - 1; |
| } |
| |
| /** |
| * Return a string describing an exception option. |
| */ |
| char* |
| ped_exception_get_option_string (PedExceptionOption ex_opt) |
| { |
| return option_strings [ped_log2 (ex_opt)]; |
| } |
| |
| static PedExceptionOption |
| default_handler (PedException* e) |
| { |
| if (e->type == PED_EXCEPTION_BUG) |
| fprintf (stderr, |
| _("A bug has been detected in GNU Parted. " |
| "Refer to the web site of parted " |
| "http://www.gnu.org/software/parted/parted.html " |
| "for more informations of what could be useful " |
| "for bug submitting! " |
| "Please email a bug report to " |
| "bug-parted@gnu.org containing at least the " |
| "version (%s) and the following message: "), |
| VERSION); |
| else |
| fprintf (stderr, "%s: ", |
| ped_exception_get_type_string (e->type)); |
| fprintf (stderr, "%s\n", e->message); |
| |
| switch (e->options) { |
| case PED_EXCEPTION_OK: |
| case PED_EXCEPTION_CANCEL: |
| case PED_EXCEPTION_IGNORE: |
| return e->options; |
| |
| default: |
| return PED_EXCEPTION_UNHANDLED; |
| } |
| } |
| |
| /** |
| * Set the exception handler. |
| * |
| * The exception handler should return ONE of the options set in ex->options, |
| * indicating the way the event should be resolved. |
| */ |
| void |
| ped_exception_set_handler (PedExceptionHandler* handler) |
| { |
| if (handler) |
| ex_handler = handler; |
| else |
| ex_handler = default_handler; |
| } |
| |
| /** |
| * Get the current exception handler. |
| */ |
| PedExceptionHandler * |
| ped_exception_get_handler (void) |
| { |
| if (ex_handler) |
| return ex_handler; |
| return default_handler; |
| } |
| |
| /** |
| * Assert that the current exception has been resolved. |
| */ |
| void |
| ped_exception_catch () |
| { |
| if (ped_exception) { |
| ped_exception = 0; |
| |
| ped_free (ex->message); |
| ped_free (ex); |
| ex = NULL; |
| } |
| } |
| |
| static PedExceptionOption |
| do_throw () |
| { |
| PedExceptionOption ex_opt; |
| |
| ped_exception = 1; |
| |
| if (ex_fetch_count) { |
| return PED_EXCEPTION_UNHANDLED; |
| } else { |
| ex_opt = ex_handler (ex); |
| ped_exception_catch (); |
| return ex_opt; |
| } |
| } |
| |
| /** |
| * Throw an exception. |
| * |
| * You can also use this in a program using libparted. |
| * "message" is a printf-like format string, so you can do |
| * |
| * \code |
| * ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_CANCEL, |
| * "Can't open %s", file_name); |
| * \endcode |
| * |
| * Returns the option selected to resolve the exception. If the exception was |
| * unhandled, PED_EXCEPTION_UNHANDLED is returned. |
| */ |
| PedExceptionOption |
| ped_exception_throw (PedExceptionType ex_type, |
| PedExceptionOption ex_opts, const char* message, ...) |
| { |
| va_list arg_list; |
| int result; |
| static int size = 1000; |
| |
| if (ex) |
| ped_exception_catch (); |
| |
| ex = (PedException*) malloc (sizeof (PedException)); |
| if (!ex) |
| goto no_memory; |
| |
| ex->type = ex_type; |
| ex->options = ex_opts; |
| |
| while (1) { |
| ex->message = (char*) malloc (size); |
| if (!ex->message) |
| goto no_memory; |
| |
| va_start (arg_list, message); |
| result = vsnprintf (ex->message, size, message, arg_list); |
| va_end (arg_list); |
| |
| if (result > -1 && result < size) |
| break; |
| |
| size += 10; |
| } |
| |
| return do_throw (); |
| |
| no_memory: |
| fputs ("Out of memory in exception handler!\n", stderr); |
| |
| va_start (arg_list, message); |
| vfprintf (stderr, message, arg_list); |
| va_end (arg_list); |
| |
| return PED_EXCEPTION_UNHANDLED; |
| } |
| |
| /** |
| * Rethrow an unhandled exception. |
| * This means repeating the last ped_exception_throw() statement. |
| */ |
| PedExceptionOption |
| ped_exception_rethrow () |
| { |
| return do_throw (); |
| } |
| |
| /** |
| * Indicates that exceptions should not go to the exception handler, but |
| * passed up to the calling function(s). All calls to |
| * ped_exception_throw() will return PED_EXCEPTION_UNHANDLED. |
| */ |
| void |
| ped_exception_fetch_all () |
| { |
| ex_fetch_count++; |
| } |
| |
| /** |
| * Indicates that the calling function does not want to accept any |
| * responsibility for exceptions any more. |
| * |
| * \note a caller of that function may still want responsibility, so |
| * ped_exception_throw() may not invoke the exception handler. |
| * |
| * \warning every call to this function must have a preceding |
| * ped_exception_fetch_all(). |
| */ |
| void |
| ped_exception_leave_all () |
| { |
| PED_ASSERT (ex_fetch_count > 0, return); |
| ex_fetch_count--; |
| } |
| |
| /** @} */ |
| |