dbus-errors.c revision e0b284c7e38f0c002b2173d85ab89dc18700867c
1/* -*- mode: C; c-file-style: "gnu" -*- */ 2/* dbus-errors.c Error reporting 3 * 4 * Copyright (C) 2002 Red Hat Inc. 5 * Copyright (C) 2003 CodeFactory AB 6 * 7 * Licensed under the Academic Free License version 1.2 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 <stdarg.h> 27#include <stdio.h> 28#include <string.h> 29 30/** 31 * @defgroup DBusErrors Error reporting 32 * @ingroup DBus 33 * @brief Error reporting 34 * 35 * Types and functions related to reporting errors. 36 * 37 * 38 * In essence D-BUS error reporting works as follows: 39 * 40 * @code 41 * DBusError error; 42 * _dbus_error_init (&error); 43 * dbus_some_function (arg1, arg2, &error); 44 * if (dbus_error_is_set (&error)) 45 * { 46 * fprintf (stderr, "an error occurred: %s\n", error.message); 47 * dbus_error_free (&error); 48 * } 49 * @endcode 50 * 51 * There are some rules. An error passed to a D-BUS function must 52 * always be unset; you can't pass in an error that's already set. If 53 * a function has a return code indicating whether an error occurred, 54 * and also a #DBusError parameter, then the error will always be set 55 * if and only if the return code indicates an error occurred. i.e. 56 * the return code and the error are never going to disagree. 57 * 58 * An error only needs to be freed if it's been set, not if 59 * it's merely been initialized. 60 * 61 * You can check the specific error that occurred using 62 * dbus_error_has_name(). 63 * 64 * @{ 65 */ 66 67typedef struct 68{ 69 const char *name; /**< error name */ 70 char *message; /**< error message */ 71 72 unsigned int const_message : 1; /** Message is not owned by DBusError */ 73 74 unsigned int dummy2 : 1; /**< placeholder */ 75 unsigned int dummy3 : 1; /**< placeholder */ 76 unsigned int dummy4 : 1; /**< placeholder */ 77 unsigned int dummy5 : 1; /**< placeholder */ 78 79 void *padding1; /**< placeholder */ 80 81} DBusRealError; 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 */ 91static const char* 92message_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 argumemts."; 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 127 return error; 128} 129 130/** 131 * Initializes a DBusError structure. Does not allocate 132 * any memory; the error only needs to be freed 133 * if it is set at some point. 134 * 135 * @param error the DBusError. 136 */ 137void 138dbus_error_init (DBusError *error) 139{ 140 DBusRealError *real; 141 142 _dbus_assert (error != NULL); 143 144 _dbus_assert (sizeof (DBusError) == sizeof (DBusRealError)); 145 146 real = (DBusRealError *)error; 147 148 real->name = NULL; 149 real->message = NULL; 150 151 real->const_message = TRUE; 152} 153 154/** 155 * Frees an error that's been set (or just initialized), 156 * then reinitializes the error as in dbus_error_init(). 157 * 158 * @param error memory where the error is stored. 159 */ 160void 161dbus_error_free (DBusError *error) 162{ 163 DBusRealError *real; 164 165 real = (DBusRealError *)error; 166 167 if (!real->const_message) 168 dbus_free (real->message); 169 170 dbus_error_init (error); 171} 172 173/** 174 * Assigns an error name and message to a DBusError. Does nothing if 175 * error is #NULL. The message may be NULL, which means a default 176 * message will be deduced from the name. If the error name is unknown 177 * to D-BUS the default message will be totally useless, though. 178 * 179 * @param error the error. 180 * @param name the error name (not copied!!!) 181 * @param message the error message (not copied!!!) 182 */ 183void 184dbus_set_error_const (DBusError *error, 185 const char *name, 186 const char *message) 187{ 188 DBusRealError *real; 189 190 if (error == NULL) 191 return; 192 193 /* it's a bug to pile up errors */ 194 _dbus_assert (error->name == NULL); 195 _dbus_assert (error->message == NULL); 196 _dbus_assert (name != NULL); 197 198 if (message == NULL) 199 message = message_from_error (name); 200 201 real = (DBusRealError *)error; 202 203 real->name = name; 204 real->message = (char *)message; 205 real->const_message = TRUE; 206} 207 208/** 209 * Moves an error src into dest, freeing src and 210 * overwriting dest. Both src and dest must be initialized. 211 * src is reinitialized to an empty error. dest may not 212 * contain an existing error. If the destination is 213 * #NULL, just frees and reinits the source error. 214 * 215 * @param src the source error 216 * @param dest the destination error or #NULL 217 */ 218void 219dbus_move_error (DBusError *src, 220 DBusError *dest) 221{ 222 _dbus_assert (!dbus_error_is_set (dest)); 223 224 if (dest) 225 { 226 dbus_error_free (dest); 227 *dest = *src; 228 dbus_error_init (src); 229 } 230 else 231 dbus_error_free (src); 232} 233 234/** 235 * Checks whether the error is set and has the given 236 * name. 237 * @param error the error 238 * @param name the name 239 * @returns #TRUE if the given named error occurred 240 */ 241dbus_bool_t 242dbus_error_has_name (const DBusError *error, 243 const char *name) 244{ 245 _dbus_assert (error != NULL); 246 _dbus_assert (name != NULL); 247 _dbus_assert ((error->name != NULL && error->message != NULL) || 248 (error->name == NULL && error->message == NULL)); 249 250 if (error->name != NULL) 251 { 252 DBusString str1, str2; 253 _dbus_string_init_const (&str1, error->name); 254 _dbus_string_init_const (&str2, name); 255 return _dbus_string_equal (&str1, &str2); 256 } 257 else 258 return FALSE; 259} 260 261/** 262 * Checks whether an error occurred (the error is set). 263 * 264 * @param error the error object 265 * @returns #TRUE if an error occurred 266 */ 267dbus_bool_t 268dbus_error_is_set (const DBusError *error) 269{ 270 _dbus_assert (error != NULL); 271 _dbus_assert ((error->name != NULL && error->message != NULL) || 272 (error->name == NULL && error->message == NULL)); 273 return error->name != NULL; 274} 275 276/** 277 * Assigns an error name and message to a DBusError. 278 * Does nothing if error is #NULL. 279 * 280 * The format may be NULL, which means a default message will be 281 * deduced from the name. If the error name is unknown to D-BUS the 282 * default message will be totally useless, though. 283 * 284 * If no memory can be allocated for the error message, 285 * an out-of-memory error message will be set instead. 286 * 287 * @todo stdio.h shouldn't be included in this file, 288 * should write _dbus_string_append_printf instead 289 * 290 * @param error the error. 291 * @param name the error name (not copied!!!) 292 * @param format printf-style format string. 293 */ 294void 295dbus_set_error (DBusError *error, 296 const char *name, 297 const char *format, 298 ...) 299{ 300 DBusRealError *real; 301 va_list args; 302 int message_length; 303 char *message; 304 char c; 305 306 if (error == NULL) 307 return; 308 309 /* it's a bug to pile up errors */ 310 _dbus_assert (error->name == NULL); 311 _dbus_assert (error->message == NULL); 312 _dbus_assert (name != NULL); 313 314 if (format == NULL) 315 format = message_from_error (name); 316 317 va_start (args, format); 318 /* Measure the message length */ 319 message_length = vsnprintf (&c, 1, format, args) + 1; 320 va_end (args); 321 322 message = dbus_malloc (message_length); 323 324 if (!message) 325 { 326 dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL); 327 return; 328 } 329 330 va_start (args, format); 331 vsprintf (message, format, args); 332 va_end (args); 333 334 real = (DBusRealError *)error; 335 336 real->name = name; 337 real->message = message; 338 real->const_message = FALSE; 339} 340 341/** @} */ 342