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