• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-errors.c Error reporting
3  *
4  * Copyright (C) 2002, 2004  Red Hat Inc.
5  * Copyright (C) 2003  CodeFactory AB
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24 
25 #include <config.h>
26 #include "dbus-errors.h"
27 #include "dbus-internals.h"
28 #include "dbus-string.h"
29 #include "dbus-protocol.h"
30 #include <stdarg.h>
31 #include <string.h>
32 
33 /**
34  * @defgroup DBusErrorInternals Error reporting internals
35  * @ingroup  DBusInternals
36  * @brief Error reporting internals
37  * @{
38  */
39 
40 /**
41  * @def DBUS_ERROR_INIT
42  *
43  * Expands to a suitable initializer for a DBusError on the stack.
44  * Declaring a DBusError with:
45  *
46  * @code
47  * DBusError error = DBUS_ERROR_INIT;
48  *
49  * do_things_with (&error);
50  * @endcode
51  *
52  * is a more concise form of:
53  *
54  * @code
55  * DBusError error;
56  *
57  * dbus_error_init (&error);
58  * do_things_with (&error);
59  * @endcode
60  */
61 
62 /**
63  * Internals of DBusError
64  */
65 typedef struct
66 {
67   char *name; /**< error name */
68   char *message; /**< error message */
69 
70   unsigned int const_message : 1; /**< Message is not owned by DBusError */
71 
72   unsigned int dummy2 : 1; /**< placeholder */
73   unsigned int dummy3 : 1; /**< placeholder */
74   unsigned int dummy4 : 1; /**< placeholder */
75   unsigned int dummy5 : 1; /**< placeholder */
76 
77   void *padding1; /**< placeholder */
78 
79 } DBusRealError;
80 
81 _DBUS_STATIC_ASSERT (sizeof (DBusRealError) == sizeof (DBusError));
82 
83 /**
84  * Returns a longer message describing an error name.
85  * If the error name is unknown, returns the name
86  * itself.
87  *
88  * @param error the error to describe
89  * @returns a constant string describing the error.
90  */
91 static const char*
message_from_error(const char * error)92 message_from_error (const char *error)
93 {
94   if (strcmp (error, DBUS_ERROR_FAILED) == 0)
95     return "Unknown error";
96   else if (strcmp (error, DBUS_ERROR_NO_MEMORY) == 0)
97     return "Not enough memory available";
98   else if (strcmp (error, DBUS_ERROR_IO_ERROR) == 0)
99     return "Error reading or writing data";
100   else if (strcmp (error, DBUS_ERROR_BAD_ADDRESS) == 0)
101     return "Could not parse address";
102   else if (strcmp (error, DBUS_ERROR_NOT_SUPPORTED) == 0)
103     return "Feature not supported";
104   else if (strcmp (error, DBUS_ERROR_LIMITS_EXCEEDED) == 0)
105     return "Resource limits exceeded";
106   else if (strcmp (error, DBUS_ERROR_ACCESS_DENIED) == 0)
107     return "Permission denied";
108   else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0)
109     return "Could not authenticate to server";
110   else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0)
111     return "No server available at address";
112   else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0)
113     return "Connection timed out";
114   else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0)
115     return "Network unavailable";
116   else if (strcmp (error, DBUS_ERROR_ADDRESS_IN_USE) == 0)
117     return "Address already in use";
118   else if (strcmp (error, DBUS_ERROR_DISCONNECTED) == 0)
119     return "Disconnected.";
120   else if (strcmp (error, DBUS_ERROR_INVALID_ARGS) == 0)
121     return "Invalid arguments.";
122   else if (strcmp (error, DBUS_ERROR_NO_REPLY) == 0)
123     return "Did not get a reply message.";
124   else if (strcmp (error, DBUS_ERROR_FILE_NOT_FOUND) == 0)
125     return "File doesn't exist.";
126   else if (strcmp (error, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0)
127     return "Object path already in use";
128   else
129     return error;
130 }
131 
132 /** @} */ /* End of internals */
133 
134 /**
135  * @defgroup DBusErrors Error reporting
136  * @ingroup  DBus
137  * @brief Error reporting
138  *
139  * Types and functions related to reporting errors.
140  *
141  *
142  * In essence D-Bus error reporting works as follows:
143  *
144  * @code
145  * DBusError error;
146  * dbus_error_init (&error);
147  * dbus_some_function (arg1, arg2, &error);
148  * if (dbus_error_is_set (&error))
149  *   {
150  *     fprintf (stderr, "an error occurred: %s\n", error.message);
151  *     dbus_error_free (&error);
152  *   }
153  * @endcode
154  *
155  * By convention, all functions allow #NULL instead of a DBusError*,
156  * so callers who don't care about the error can ignore it.
157  *
158  * There are some rules. An error passed to a D-Bus function must
159  * always be unset; you can't pass in an error that's already set.  If
160  * a function has a return code indicating whether an error occurred,
161  * and also a #DBusError parameter, then the error will always be set
162  * if and only if the return code indicates an error occurred. i.e.
163  * the return code and the error are never going to disagree.
164  *
165  * An error only needs to be freed if it's been set, not if
166  * it's merely been initialized.
167  *
168  * You can check the specific error that occurred using
169  * dbus_error_has_name().
170  *
171  * Errors will not be set for programming errors, such as passing
172  * invalid arguments to the libdbus API. Instead, libdbus will print
173  * warnings, exit on a failed assertion, or even crash in those cases
174  * (in other words, incorrect use of the API results in undefined
175  * behavior, possibly accompanied by helpful debugging output if
176  * you're lucky).
177  *
178  * @{
179  */
180 
181 /**
182  * Initializes a DBusError structure. Does not allocate any memory;
183  * the error only needs to be freed if it is set at some point.
184  *
185  * @param error the DBusError.
186  */
187 void
dbus_error_init(DBusError * error)188 dbus_error_init (DBusError *error)
189 {
190   DBusRealError *real;
191 
192   _dbus_return_if_fail (error != NULL);
193 
194   _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError));
195 
196   real = (DBusRealError *)error;
197 
198   real->name = NULL;
199   real->message = NULL;
200 
201   real->const_message = TRUE;
202 }
203 
204 /**
205  * Frees an error that's been set (or just initialized),
206  * then reinitializes the error as in dbus_error_init().
207  *
208  * @param error memory where the error is stored.
209  */
210 void
dbus_error_free(DBusError * error)211 dbus_error_free (DBusError *error)
212 {
213   DBusRealError *real;
214 
215   _dbus_return_if_fail (error != NULL);
216 
217   real = (DBusRealError *)error;
218 
219   if (!real->const_message)
220     {
221       dbus_free (real->name);
222       dbus_free (real->message);
223     }
224 
225   dbus_error_init (error);
226 }
227 
228 /**
229  * Assigns an error name and message to a DBusError.  Does nothing if
230  * error is #NULL. The message may be #NULL, which means a default
231  * message will be deduced from the name. The default message will be
232  * totally useless, though, so using a #NULL message is not recommended.
233  *
234  * Because this function does not copy the error name or message, you
235  * must ensure the name and message are global data that won't be
236  * freed. You probably want dbus_set_error() instead, in most cases.
237  *
238  * @param error the error.or #NULL
239  * @param name the error name (not copied!!!)
240  * @param message the error message (not copied!!!)
241  */
242 void
dbus_set_error_const(DBusError * error,const char * name,const char * message)243 dbus_set_error_const (DBusError  *error,
244 		      const char *name,
245 		      const char *message)
246 {
247   DBusRealError *real;
248 
249   _dbus_return_if_error_is_set (error);
250   _dbus_return_if_fail (name != NULL);
251 
252   if (error == NULL)
253     return;
254 
255   _dbus_assert (error->name == NULL);
256   _dbus_assert (error->message == NULL);
257 
258   if (message == NULL)
259     message = message_from_error (name);
260 
261   real = (DBusRealError *)error;
262 
263   real->name = (char*) name;
264   real->message = (char *)message;
265   real->const_message = TRUE;
266 }
267 
268 /**
269  * Moves an error src into dest, freeing src and
270  * overwriting dest. Both src and dest must be initialized.
271  * src is reinitialized to an empty error. dest may not
272  * contain an existing error. If the destination is
273  * #NULL, just frees and reinits the source error.
274  *
275  * @param src the source error
276  * @param dest the destination error or #NULL
277  */
278 void
dbus_move_error(DBusError * src,DBusError * dest)279 dbus_move_error (DBusError *src,
280                  DBusError *dest)
281 {
282   _dbus_return_if_error_is_set (dest);
283 
284   if (dest)
285     {
286       dbus_error_free (dest);
287       *dest = *src;
288       dbus_error_init (src);
289     }
290   else
291     dbus_error_free (src);
292 }
293 
294 /**
295  * Checks whether the error is set and has the given
296  * name.
297  * @param error the error
298  * @param name the name
299  * @returns #TRUE if the given named error occurred
300  */
301 dbus_bool_t
dbus_error_has_name(const DBusError * error,const char * name)302 dbus_error_has_name (const DBusError *error,
303                      const char      *name)
304 {
305   _dbus_return_val_if_fail (error != NULL, FALSE);
306   _dbus_return_val_if_fail (name != NULL, FALSE);
307 
308   _dbus_assert ((error->name != NULL && error->message != NULL) ||
309                 (error->name == NULL && error->message == NULL));
310 
311   if (error->name != NULL)
312     {
313       DBusString str1, str2;
314       _dbus_string_init_const (&str1, error->name);
315       _dbus_string_init_const (&str2, name);
316       return _dbus_string_equal (&str1, &str2);
317     }
318   else
319     return FALSE;
320 }
321 
322 /**
323  * Checks whether an error occurred (the error is set).
324  *
325  * @param error the error object
326  * @returns #TRUE if an error occurred
327  */
328 dbus_bool_t
dbus_error_is_set(const DBusError * error)329 dbus_error_is_set (const DBusError *error)
330 {
331   _dbus_return_val_if_fail (error != NULL, FALSE);
332   _dbus_assert ((error->name != NULL && error->message != NULL) ||
333                 (error->name == NULL && error->message == NULL));
334   return error->name != NULL;
335 }
336 
337 /**
338  * Assigns an error name and message to a DBusError.
339  * Does nothing if error is #NULL.
340  *
341  * The format may be #NULL, which means a (pretty much useless)
342  * default message will be deduced from the name. This is not a good
343  * idea, just go ahead and provide a useful error message. It won't
344  * hurt you.
345  *
346  * If no memory can be allocated for the error message,
347  * an out-of-memory error message will be set instead.
348  *
349  * @param error the error.or #NULL
350  * @param name the error name
351  * @param format printf-style format string.
352  */
353 void
dbus_set_error(DBusError * error,const char * name,const char * format,...)354 dbus_set_error (DBusError  *error,
355 		const char *name,
356 		const char *format,
357 		...)
358 {
359   DBusRealError *real;
360   DBusString str;
361   va_list args;
362 
363   if (error == NULL)
364     return;
365 
366   /* it's a bug to pile up errors */
367   _dbus_return_if_error_is_set (error);
368   _dbus_return_if_fail (name != NULL);
369 
370   _dbus_assert (error->name == NULL);
371   _dbus_assert (error->message == NULL);
372 
373   if (!_dbus_string_init (&str))
374     goto nomem;
375 
376   if (format == NULL)
377     {
378       if (!_dbus_string_append (&str,
379                                 message_from_error (name)))
380         {
381           _dbus_string_free (&str);
382           va_end (args);
383           goto nomem;
384         }
385     }
386   else
387     {
388       va_start (args, format);
389       if (!_dbus_string_append_printf_valist (&str, format, args))
390         {
391           _dbus_string_free (&str);
392           va_end (args);
393           goto nomem;
394         }
395       va_end (args);
396     }
397 
398   real = (DBusRealError *)error;
399 
400   if (!_dbus_string_steal_data (&str, &real->message))
401     {
402       _dbus_string_free (&str);
403       goto nomem;
404     }
405   _dbus_string_free (&str);
406 
407   real->name = _dbus_strdup (name);
408   if (real->name == NULL)
409     {
410       dbus_free (real->message);
411       real->message = NULL;
412       goto nomem;
413     }
414   real->const_message = FALSE;
415 
416   return;
417 
418  nomem:
419   _DBUS_SET_OOM (error);
420 }
421 
422 /** @} */ /* End public API */
423