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