Home | History | Annotate | Download | only in dbus
      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*
     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
    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
    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
    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
    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
    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
    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
    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