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 /**
     82  * Returns a longer message describing an error name.
     83  * If the error name is unknown, returns the name
     84  * itself.
     85  *
     86  * @param error the error to describe
     87  * @returns a constant string describing the error.
     88  */
     89 static const char*
     90 message_from_error (const char *error)
     91 {
     92   if (strcmp (error, DBUS_ERROR_FAILED) == 0)
     93     return "Unknown error";
     94   else if (strcmp (error, DBUS_ERROR_NO_MEMORY) == 0)
     95     return "Not enough memory available";
     96   else if (strcmp (error, DBUS_ERROR_IO_ERROR) == 0)
     97     return "Error reading or writing data";
     98   else if (strcmp (error, DBUS_ERROR_BAD_ADDRESS) == 0)
     99     return "Could not parse address";
    100   else if (strcmp (error, DBUS_ERROR_NOT_SUPPORTED) == 0)
    101     return "Feature not supported";
    102   else if (strcmp (error, DBUS_ERROR_LIMITS_EXCEEDED) == 0)
    103     return "Resource limits exceeded";
    104   else if (strcmp (error, DBUS_ERROR_ACCESS_DENIED) == 0)
    105     return "Permission denied";
    106   else if (strcmp (error, DBUS_ERROR_AUTH_FAILED) == 0)
    107     return "Could not authenticate to server";
    108   else if (strcmp (error, DBUS_ERROR_NO_SERVER) == 0)
    109     return "No server available at address";
    110   else if (strcmp (error, DBUS_ERROR_TIMEOUT) == 0)
    111     return "Connection timed out";
    112   else if (strcmp (error, DBUS_ERROR_NO_NETWORK) == 0)
    113     return "Network unavailable";
    114   else if (strcmp (error, DBUS_ERROR_ADDRESS_IN_USE) == 0)
    115     return "Address already in use";
    116   else if (strcmp (error, DBUS_ERROR_DISCONNECTED) == 0)
    117     return "Disconnected.";
    118   else if (strcmp (error, DBUS_ERROR_INVALID_ARGS) == 0)
    119     return "Invalid arguments.";
    120   else if (strcmp (error, DBUS_ERROR_NO_REPLY) == 0)
    121     return "Did not get a reply message.";
    122   else if (strcmp (error, DBUS_ERROR_FILE_NOT_FOUND) == 0)
    123     return "File doesn't exist.";
    124   else if (strcmp (error, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0)
    125     return "Object path already in use";
    126   else
    127     return error;
    128 }
    129 
    130 /** @} */ /* End of internals */
    131 
    132 /**
    133  * @defgroup DBusErrors Error reporting
    134  * @ingroup  DBus
    135  * @brief Error reporting
    136  *
    137  * Types and functions related to reporting errors.
    138  *
    139  *
    140  * In essence D-Bus error reporting works as follows:
    141  *
    142  * @code
    143  * DBusError error;
    144  * dbus_error_init (&error);
    145  * dbus_some_function (arg1, arg2, &error);
    146  * if (dbus_error_is_set (&error))
    147  *   {
    148  *     fprintf (stderr, "an error occurred: %s\n", error.message);
    149  *     dbus_error_free (&error);
    150  *   }
    151  * @endcode
    152  *
    153  * By convention, all functions allow #NULL instead of a DBusError*,
    154  * so callers who don't care about the error can ignore it.
    155  *
    156  * There are some rules. An error passed to a D-Bus function must
    157  * always be unset; you can't pass in an error that's already set.  If
    158  * a function has a return code indicating whether an error occurred,
    159  * and also a #DBusError parameter, then the error will always be set
    160  * if and only if the return code indicates an error occurred. i.e.
    161  * the return code and the error are never going to disagree.
    162  *
    163  * An error only needs to be freed if it's been set, not if
    164  * it's merely been initialized.
    165  *
    166  * You can check the specific error that occurred using
    167  * dbus_error_has_name().
    168  *
    169  * Errors will not be set for programming errors, such as passing
    170  * invalid arguments to the libdbus API. Instead, libdbus will print
    171  * warnings, exit on a failed assertion, or even crash in those cases
    172  * (in other words, incorrect use of the API results in undefined
    173  * behavior, possibly accompanied by helpful debugging output if
    174  * you're lucky).
    175  *
    176  * @{
    177  */
    178 
    179 /**
    180  * Initializes a DBusError structure. Does not allocate any memory;
    181  * the error only needs to be freed if it is set at some point.
    182  *
    183  * @param error the DBusError.
    184  */
    185 void
    186 dbus_error_init (DBusError *error)
    187 {
    188   DBusRealError *real;
    189 
    190   _dbus_return_if_fail (error != NULL);
    191 
    192   _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError));
    193 
    194   real = (DBusRealError *)error;
    195 
    196   real->name = NULL;
    197   real->message = NULL;
    198 
    199   real->const_message = TRUE;
    200 }
    201 
    202 /**
    203  * Frees an error that's been set (or just initialized),
    204  * then reinitializes the error as in dbus_error_init().
    205  *
    206  * @param error memory where the error is stored.
    207  */
    208 void
    209 dbus_error_free (DBusError *error)
    210 {
    211   DBusRealError *real;
    212 
    213   _dbus_return_if_fail (error != NULL);
    214 
    215   real = (DBusRealError *)error;
    216 
    217   if (!real->const_message)
    218     {
    219       dbus_free (real->name);
    220       dbus_free (real->message);
    221     }
    222 
    223   dbus_error_init (error);
    224 }
    225 
    226 /**
    227  * Assigns an error name and message to a DBusError.  Does nothing if
    228  * error is #NULL. The message may be #NULL, which means a default
    229  * message will be deduced from the name. The default message will be
    230  * totally useless, though, so using a #NULL message is not recommended.
    231  *
    232  * Because this function does not copy the error name or message, you
    233  * must ensure the name and message are global data that won't be
    234  * freed. You probably want dbus_set_error() instead, in most cases.
    235  *
    236  * @param error the error.or #NULL
    237  * @param name the error name (not copied!!!)
    238  * @param message the error message (not copied!!!)
    239  */
    240 void
    241 dbus_set_error_const (DBusError  *error,
    242 		      const char *name,
    243 		      const char *message)
    244 {
    245   DBusRealError *real;
    246 
    247   _dbus_return_if_error_is_set (error);
    248   _dbus_return_if_fail (name != NULL);
    249 
    250   if (error == NULL)
    251     return;
    252 
    253   _dbus_assert (error->name == NULL);
    254   _dbus_assert (error->message == NULL);
    255 
    256   if (message == NULL)
    257     message = message_from_error (name);
    258 
    259   real = (DBusRealError *)error;
    260 
    261   real->name = (char*) name;
    262   real->message = (char *)message;
    263   real->const_message = TRUE;
    264 }
    265 
    266 /**
    267  * Moves an error src into dest, freeing src and
    268  * overwriting dest. Both src and dest must be initialized.
    269  * src is reinitialized to an empty error. dest may not
    270  * contain an existing error. If the destination is
    271  * #NULL, just frees and reinits the source error.
    272  *
    273  * @param src the source error
    274  * @param dest the destination error or #NULL
    275  */
    276 void
    277 dbus_move_error (DBusError *src,
    278                  DBusError *dest)
    279 {
    280   _dbus_return_if_error_is_set (dest);
    281 
    282   if (dest)
    283     {
    284       dbus_error_free (dest);
    285       *dest = *src;
    286       dbus_error_init (src);
    287     }
    288   else
    289     dbus_error_free (src);
    290 }
    291 
    292 /**
    293  * Checks whether the error is set and has the given
    294  * name.
    295  * @param error the error
    296  * @param name the name
    297  * @returns #TRUE if the given named error occurred
    298  */
    299 dbus_bool_t
    300 dbus_error_has_name (const DBusError *error,
    301                      const char      *name)
    302 {
    303   _dbus_return_val_if_fail (error != NULL, FALSE);
    304   _dbus_return_val_if_fail (name != NULL, FALSE);
    305 
    306   _dbus_assert ((error->name != NULL && error->message != NULL) ||
    307                 (error->name == NULL && error->message == NULL));
    308 
    309   if (error->name != NULL)
    310     {
    311       DBusString str1, str2;
    312       _dbus_string_init_const (&str1, error->name);
    313       _dbus_string_init_const (&str2, name);
    314       return _dbus_string_equal (&str1, &str2);
    315     }
    316   else
    317     return FALSE;
    318 }
    319 
    320 /**
    321  * Checks whether an error occurred (the error is set).
    322  *
    323  * @param error the error object
    324  * @returns #TRUE if an error occurred
    325  */
    326 dbus_bool_t
    327 dbus_error_is_set (const DBusError *error)
    328 {
    329   _dbus_return_val_if_fail (error != NULL, FALSE);
    330   _dbus_assert ((error->name != NULL && error->message != NULL) ||
    331                 (error->name == NULL && error->message == NULL));
    332   return error->name != NULL;
    333 }
    334 
    335 /**
    336  * Assigns an error name and message to a DBusError.
    337  * Does nothing if error is #NULL.
    338  *
    339  * The format may be #NULL, which means a (pretty much useless)
    340  * default message will be deduced from the name. This is not a good
    341  * idea, just go ahead and provide a useful error message. It won't
    342  * hurt you.
    343  *
    344  * If no memory can be allocated for the error message,
    345  * an out-of-memory error message will be set instead.
    346  *
    347  * @param error the error.or #NULL
    348  * @param name the error name
    349  * @param format printf-style format string.
    350  */
    351 void
    352 dbus_set_error (DBusError  *error,
    353 		const char *name,
    354 		const char *format,
    355 		...)
    356 {
    357   DBusRealError *real;
    358   DBusString str;
    359   va_list args;
    360 
    361   if (error == NULL)
    362     return;
    363 
    364   /* it's a bug to pile up errors */
    365   _dbus_return_if_error_is_set (error);
    366   _dbus_return_if_fail (name != NULL);
    367 
    368   _dbus_assert (error->name == NULL);
    369   _dbus_assert (error->message == NULL);
    370 
    371   if (!_dbus_string_init (&str))
    372     goto nomem;
    373 
    374   if (format == NULL)
    375     {
    376       if (!_dbus_string_append (&str,
    377                                 message_from_error (name)))
    378         {
    379           _dbus_string_free (&str);
    380           va_end (args);
    381           goto nomem;
    382         }
    383     }
    384   else
    385     {
    386       va_start (args, format);
    387       if (!_dbus_string_append_printf_valist (&str, format, args))
    388         {
    389           _dbus_string_free (&str);
    390           va_end (args);
    391           goto nomem;
    392         }
    393       va_end (args);
    394     }
    395 
    396   real = (DBusRealError *)error;
    397 
    398   if (!_dbus_string_steal_data (&str, &real->message))
    399     {
    400       _dbus_string_free (&str);
    401       goto nomem;
    402     }
    403   _dbus_string_free (&str);
    404 
    405   real->name = _dbus_strdup (name);
    406   if (real->name == NULL)
    407     {
    408       dbus_free (real->message);
    409       real->message = NULL;
    410       goto nomem;
    411     }
    412   real->const_message = FALSE;
    413 
    414   return;
    415 
    416  nomem:
    417   _DBUS_SET_OOM (error);
    418 }
    419 
    420 /** @} */ /* End public API */
    421