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