OSDN Git Service

lib-fs-resize: remove unused probe-related code
[android-x86/external-parted.git] / libparted / exception.c
1 /*
2     libparted - a library for manipulating disk partitions
3     Copyright (C) 1999-2000, 2007-2012 Free Software Foundation, Inc.
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /** \file exception.c */
20
21 /**
22  * \addtogroup PedException
23  *
24  * \brief Exception handling.
25  *
26  * There are a few types of exceptions: PED_EXCEPTION_INFORMATION,
27  * PED_EXCEPTION_WARNING, PED_EXCEPTION_ERROR, PED_EXCEPTION_FATAL,
28  * PED_EXCEPTION_BUG.
29  *
30  * They are "thrown" when one of the above events occur while executing
31  * a libparted function. For example, if ped_device_open() fails
32  * because the device doesn't exist, an exception will be thrown.
33  * Exceptions contain text describing what the event was. It will give
34  * at least one option for resolving the exception: PED_EXCEPTION_FIX,
35  * PED_EXCEPTION_YES, PED_EXCEPTION_NO, PED_EXCEPTION_OK, PED_EXCEPTION_RETRY,
36  * PED_EXCEPTION_IGNORE, PED_EXCEPTION_CANCEL. After an exception is thrown,
37  * there are two things that can happen:
38  *
39  * -# an exception handler is called, which selects how the exception should be
40  *    resolved (usually by asking the user). Also note: an exception handler may
41  *    choose to return PED_EXCEPTION_UNHANDLED. In this case, a default action
42  *    will be taken by libparted (respectively the code that threw the
43  *    exception). In general, a default action will be "safe".
44  * -# the exception is not handled, because the caller of the function wants to
45  *    handle everything itself. In this case, PED_EXCEPTION_UNHANDLED is
46  *    returned.
47  *
48  * @{
49  */
50
51 #include <config.h>
52
53 #include <parted/parted.h>
54 #include <parted/debug.h>
55 #include <parted/exception.h>
56
57 #define N_(String) String
58 #if ENABLE_NLS
59 #  include <libintl.h>
60 #  define _(String) dgettext (PACKAGE, String)
61 #else
62 #  define _(String) (String)
63 #endif /* ENABLE_NLS */
64
65 #include <stdio.h>
66 #include <stdarg.h>
67 #include <stdlib.h>
68
69 int                             ped_exception = 0;
70
71 static PedExceptionOption default_handler (PedException* ex);
72
73 static PedExceptionHandler*     ex_handler = default_handler;
74 static PedException*            ex = NULL;
75 static int                      ex_fetch_count = 0;
76
77 static const char *const type_strings [] = {
78         N_("Information"),
79         N_("Warning"),
80         N_("Error"),
81         N_("Fatal"),
82         N_("Bug"),
83         N_("No Implementation")
84 };
85
86 static const char *const option_strings [] = {
87         N_("Fix"),
88         N_("Yes"),
89         N_("No"),
90         N_("OK"),
91         N_("Retry"),
92         N_("Ignore"),
93         N_("Cancel")
94 };
95
96 /**
97  *  Return a string describing an exception type.
98  */
99 char*
100 ped_exception_get_type_string (PedExceptionType ex_type)
101 {
102         return (char *) type_strings [ex_type - 1];
103 }
104
105 /* FIXME: move this out to the prospective math.c */
106 /* FIXME: this can probably be done more efficiently */
107 static int _GL_ATTRIBUTE_PURE
108 ped_log2 (int n)
109 {
110         int x;
111
112         PED_ASSERT (n > 0);
113
114         for (x=0; 1 << x <= n; x++);
115
116         return x - 1;
117 }
118
119 /**
120  * Return a string describing an exception option.
121  */
122 char*
123 ped_exception_get_option_string (PedExceptionOption ex_opt)
124 {
125         return (char *) option_strings [ped_log2 (ex_opt)];
126 }
127
128 static PedExceptionOption
129 default_handler (PedException* e)
130 {
131         if (e->type == PED_EXCEPTION_BUG)
132                 fprintf (stderr,
133                         _("A bug has been detected in GNU Parted.  "
134                         "Refer to the web site of parted "
135                         "http://www.gnu.org/software/parted/parted.html "
136                         "for more information of what could be useful "
137                         "for bug submitting!  "
138                         "Please email a bug report to "
139                         "%s containing at least the "
140                         "version (%s) and the following message:  "),
141                          PACKAGE_BUGREPORT, VERSION);
142         else
143                 fprintf (stderr, "%s: ",
144                          ped_exception_get_type_string (e->type));
145         fprintf (stderr, "%s\n", e->message);
146
147         switch (e->options) {
148                 case PED_EXCEPTION_OK:
149                 case PED_EXCEPTION_CANCEL:
150                 case PED_EXCEPTION_IGNORE:
151                         return e->options;
152
153                 default:
154                         return PED_EXCEPTION_UNHANDLED;
155         }
156 }
157
158 /**
159  * Set the exception handler.
160  *
161  * The exception handler should return ONE of the options set in ex->options,
162  * indicating the way the event should be resolved.
163  */
164 void
165 ped_exception_set_handler (PedExceptionHandler* handler)
166 {
167         if (handler)
168                 ex_handler = handler;
169         else
170                 ex_handler = default_handler;
171 }
172
173 /**
174  * Get the current exception handler.
175  */
176 PedExceptionHandler *
177 ped_exception_get_handler (void)
178 {
179         if (ex_handler)
180                 return ex_handler;
181         return default_handler;
182 }
183
184 /**
185  * Assert that the current exception has been resolved.
186  */
187 void
188 ped_exception_catch ()
189 {
190         if (ped_exception) {
191                 ped_exception = 0;
192                 free (ex->message);
193                 free (ex);
194                 ex = NULL;
195         }
196 }
197
198 static PedExceptionOption
199 do_throw ()
200 {
201         PedExceptionOption      ex_opt;
202
203         ped_exception = 1;
204
205         if (ex_fetch_count) {
206                 return PED_EXCEPTION_UNHANDLED;
207         } else {
208                 ex_opt = ex_handler (ex);
209                 ped_exception_catch ();
210                 return ex_opt;
211         }
212 }
213
214 /**
215  * Throw an exception.
216  *
217  * You can also use this in a program using libparted.
218  * "message" is a printf-like format string, so you can do
219  *
220  * \code
221  * ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_CANCEL,
222  *      "Can't open %s", file_name);
223  * \endcode
224  *
225  * Returns the option selected to resolve the exception. If the exception was
226  * unhandled, PED_EXCEPTION_UNHANDLED is returned.
227  */
228 PedExceptionOption
229 ped_exception_throw (PedExceptionType ex_type,
230                      PedExceptionOption ex_opts, const char* message, ...)
231 {
232         va_list         arg_list;
233         int result;
234         static int size = 1000;
235
236         if (ex)
237                 ped_exception_catch ();
238
239         ex = (PedException*) malloc (sizeof (PedException));
240         if (!ex)
241                 goto no_memory;
242
243         ex->type = ex_type;
244         ex->options = ex_opts;
245
246         while (message) {
247                         ex->message = (char*) malloc (size * sizeof (char));
248                         if (!ex->message)
249                                         goto no_memory;
250
251                         va_start (arg_list, message);
252                         result = vsnprintf (ex->message, size, message, arg_list);
253                         va_end (arg_list);
254
255                         if (result > -1 && result < size)
256                                         break;
257
258                         size += 10;
259                         free (ex->message);
260         }
261
262         return do_throw ();
263
264 no_memory:
265         fputs ("Out of memory in exception handler!\n", stderr);
266
267         va_start (arg_list, message);
268         vfprintf (stderr, message, arg_list);
269         va_end (arg_list);
270
271         return PED_EXCEPTION_UNHANDLED;
272 }
273
274 /**
275  * Rethrow an unhandled exception.
276  * This means repeating the last ped_exception_throw() statement.
277  */
278 PedExceptionOption
279 ped_exception_rethrow ()
280 {
281         return do_throw ();
282 }
283
284 /**
285  * Indicates that exceptions should not go to the exception handler, but
286  * passed up to the calling function(s).  All calls to
287  * ped_exception_throw() will return PED_EXCEPTION_UNHANDLED.
288  */
289 void
290 ped_exception_fetch_all ()
291 {
292         ex_fetch_count++;
293 }
294
295 /**
296  * Indicates that the calling function does not want to accept any
297  * responsibility for exceptions any more.
298  *
299  * \note a caller of that function may still want responsibility, so
300  *      ped_exception_throw() may not invoke the exception handler.
301  *
302  * \warning every call to this function must have a preceding
303  *      ped_exception_fetch_all().
304  */
305 void
306 ped_exception_leave_all ()
307 {
308         PED_ASSERT (ex_fetch_count > 0);
309         ex_fetch_count--;
310 }
311
312 /** @} */