1 // Copyright 2012 Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "error.h" 30 31 #include <assert.h> 32 #include <err.h> 33 #include <stdarg.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 39 /// Generic hook to format an error that does not have a format callback. 40 /// 41 /// \param error Error for which to generate a message. 42 /// \param output_buffer Buffer to hold the generated message. 43 /// \param output_size Length of output_buffer. 44 static int 45 generic_format_callback(const kyua_error_t error, char* const output_buffer, 46 size_t output_size) 47 { 48 assert(error != NULL); 49 return snprintf(output_buffer, output_size, "Error '%s'", error->type_name); 50 } 51 52 53 /// Initializes an error object. 54 /// 55 /// \param error Error for which to generate a message. 56 /// \param type_name Name of the error type. 57 /// \param data Opaque data that belongs to the error, for usage by 58 /// error-specific methods like format_callback. 59 /// \param data_size Size of the opaque data object. 60 /// \param format_callback Type-specific method to generate a user 61 /// representation of the error. 62 /// 63 /// \return True if the initialization succeeds; false otherwise. If 64 /// false, the error object passed in has not been modified. 65 static bool 66 error_init(kyua_error_t const error, const char* const type_name, 67 void* const data, const size_t data_size, 68 const kyua_error_format_callback format_callback) 69 { 70 assert(data != NULL || data_size == 0); 71 assert(data_size != 0 || data == NULL); 72 73 bool ok; 74 75 if (data == NULL) { 76 error->data = NULL; 77 error->needs_free = false; 78 ok = true; 79 } else { 80 void* new_data = malloc(data_size); 81 if (new_data == NULL) { 82 ok = false; 83 } else { 84 memcpy(new_data, data, data_size); 85 error->data = new_data; 86 ok = true; 87 } 88 } 89 90 if (ok) { 91 error->type_name = type_name; 92 error->format_callback = (format_callback == NULL) ? 93 generic_format_callback : format_callback; 94 } 95 96 return ok; 97 } 98 99 100 /// Allocates and initializes a new error. 101 /// 102 /// \param type_name Name of the error type. 103 /// \param data Opaque data that belongs to the error, for usage by 104 /// error-specific methods like format_callback. 105 /// \param data_size Size of the opaque data object. 106 /// \param format_callback Type-specific method to generate a user 107 /// representation of the error. 108 /// 109 /// \return The newly initialized error, or an out of memory error. 110 kyua_error_t 111 kyua_error_new(const char* const type_name, void* const data, 112 const size_t data_size, 113 const kyua_error_format_callback format_callback) 114 { 115 assert(data != NULL || data_size == 0); 116 assert(data_size != 0 || data == NULL); 117 118 kyua_error_t error = malloc(sizeof(struct kyua_error)); 119 if (error == NULL) 120 error = kyua_oom_error_new(); 121 else { 122 if (!error_init(error, type_name, data, data_size, format_callback)) { 123 free(error); 124 error = kyua_oom_error_new(); 125 } else { 126 error->needs_free = true; 127 } 128 } 129 130 assert(error != NULL); 131 return error; 132 } 133 134 135 /// Releases an error. 136 /// 137 /// \param error The error object to release. 138 void 139 kyua_error_free(kyua_error_t error) 140 { 141 assert(error != NULL); 142 143 const bool needs_free = error->needs_free; 144 145 if (error->data != NULL) 146 free(error->data); 147 if (needs_free) 148 free(error); 149 } 150 151 152 /// Returns the "most important" of two errors. 153 /// 154 /// "Most important" is defined as: the primary error is returned if set, 155 /// otherwise the secondary error is returned. 156 /// 157 /// It is the responsibility of the caller to free the *resulting* error of this 158 /// call. The original errors passed in should not be consulted any longer, 159 /// because it is impossible to know which one was chosen. 160 /// 161 /// \param primary The primary error to compare. 162 /// \param [in,out] secondary The secondary error to compare. This is freed if 163 /// the primary error is set. 164 /// 165 /// \return Either primary or secondary. 166 kyua_error_t 167 kyua_error_subsume(kyua_error_t primary, kyua_error_t secondary) 168 { 169 if (kyua_error_is_set(primary)) { 170 if (kyua_error_is_set(secondary)) 171 kyua_error_free(secondary); 172 return primary; 173 } else { 174 return secondary; 175 } 176 } 177 178 179 /// Constructor for a no-error condition. 180 /// 181 /// \return Opaque representation of a no-error condition. 182 kyua_error_t 183 kyua_error_ok(void) 184 { 185 return NULL; 186 } 187 188 189 /// Checks if the given error object represents an error or not. 190 /// 191 /// \param error The error to check. 192 /// 193 /// \return True if the error is set. 194 bool 195 kyua_error_is_set(const kyua_error_t error) 196 { 197 return error != NULL; 198 } 199 200 201 /// Checks if the given error object is of a specific type. 202 /// 203 /// \pre The error must be set. 204 /// 205 /// \param error The error to check. 206 /// \param type_name The type of the expected error. 207 /// 208 /// \return True if the error is of type type_name. 209 bool 210 kyua_error_is_type(const kyua_error_t error, const char* type_name) 211 { 212 assert(error != NULL); 213 214 return strcmp(error->type_name, type_name) == 0; 215 } 216 217 218 /// Returns a pointer to the error-specific data. 219 /// 220 /// \pre The error must be set. 221 /// 222 /// \param error The error to query. 223 /// 224 /// \return An opaque pointer to the error data. This should only be 225 /// dereferenced by the methods of the error class that created it. 226 const void* 227 kyua_error_data(const kyua_error_t error) 228 { 229 assert(error != NULL); 230 231 return error->data; 232 } 233 234 235 /// Generates a user-friendly representation of the error. 236 /// 237 /// This cannot fail, but it is possible that the generated error does not 238 /// fit in the provided buffer. 239 /// 240 /// \pre The error must be set. 241 /// 242 /// \param error Error for which to generate a message. 243 /// \param output_buffer Buffer to hold the generated message. 244 /// \param output_size Length of output_buffer. 245 /// 246 /// \return The number of bytes written to output_buffer, or a negative value if 247 /// there was an error. 248 int 249 kyua_error_format(const kyua_error_t error, char* const output_buffer, 250 const size_t output_size) 251 { 252 assert(kyua_error_is_set(error)); 253 return error->format_callback(error, output_buffer, output_size); 254 } 255 256 257 /// Formats a string and appends an error code to it. 258 /// 259 /// \param error Error to append to the formatted message. 260 /// \param format User-specified message, as a formatting string. 261 /// \param ap List of arguments to the format string. 262 /// \param [out] output_buffer Buffer into which to write the message. 263 /// \param output_size Length of the output_buffer. 264 /// 265 /// \return The number of bytes written to output_buffer, or a negative value if 266 /// there was an error. 267 static int 268 format_user_message(const kyua_error_t error, const char* format, va_list ap, 269 char* const output_buffer, const size_t output_size) 270 { 271 assert(kyua_error_is_set(error)); 272 273 va_list ap2; 274 va_copy(ap2, ap); 275 size_t written = vsnprintf(output_buffer, output_size, format, ap2); 276 va_end(ap2); 277 if (written >= output_size) 278 return -1; 279 280 written += snprintf(output_buffer + written, output_size - written, ": "); 281 if (written >= output_size) 282 return -1; 283 284 return kyua_error_format(error, output_buffer + written, 285 output_size - written); 286 } 287 288 289 /// Version of err(3) that works with kyua_error_t objects. 290 /// 291 /// \param exit_code Error code with which to terminate the execution. 292 /// \param error Error to append to the output. 293 /// \param format User-specified message, as a formatting string. 294 /// \param ... Positional arguments to the format string. 295 /// 296 /// \post Execution terminates with exit_code. 297 void 298 kyua_error_err(const int exit_code, const kyua_error_t error, 299 const char* format, ...) 300 { 301 char buffer[2048]; 302 303 va_list ap; 304 va_start(ap, format); 305 (void)format_user_message(error, format, ap, buffer, sizeof(buffer)); 306 va_end(ap); 307 kyua_error_free(error); 308 309 errx(exit_code, "%s", buffer); 310 } 311 312 313 /// Writes an error to a file stream. 314 /// 315 /// \param stream Stream to which to write the message. 316 /// \param error Error to append to the output. This is not released. 317 /// \param format User-specified message, as a formatting string. 318 /// \param ... Positional arguments to the format string. 319 void 320 kyua_error_fprintf(FILE* stream, const kyua_error_t error, 321 const char* format, ...) 322 { 323 char buffer[2048]; 324 325 va_list ap; 326 va_start(ap, format); 327 (void)format_user_message(error, format, ap, buffer, sizeof(buffer)); 328 va_end(ap); 329 330 fprintf(stream, "%s", buffer); 331 } 332 333 334 /// Version of warn(3) that works with kyua_error_t objects. 335 /// 336 /// \param error Error to append to the output. This is not released. 337 /// \param format User-specified message, as a formatting string. 338 /// \param ... Positional arguments to the format string. 339 void 340 kyua_error_warn(const kyua_error_t error, const char* format, ...) 341 { 342 char buffer[2048]; 343 344 va_list ap; 345 va_start(ap, format); 346 (void)format_user_message(error, format, ap, buffer, sizeof(buffer)); 347 va_end(ap); 348 349 warnx("%s", buffer); 350 } 351 352 353 /// Name of an generic error type. 354 const char* const kyua_generic_error_type = "generic"; 355 356 357 /// Generates a user-friendly representation of the error. 358 /// 359 /// \pre The error must be set. 360 /// 361 /// \param error Error for which to generate a message. 362 /// \param output_buffer Buffer to hold the generated message. 363 /// \param output_size Length of output_buffer. 364 /// 365 /// \return The number of bytes written to output_buffer, or a negative value if 366 /// there was an error. 367 static int 368 generic_format(const kyua_error_t error, char* const output_buffer, 369 const size_t output_size) 370 { 371 assert(kyua_error_is_type(error, kyua_generic_error_type)); 372 373 const char* message = kyua_error_data(error); 374 return snprintf(output_buffer, output_size, "%s", message); 375 } 376 377 378 /// Constructs a new generic error. 379 /// 380 /// \param message Textual description of the problem. 381 /// \param ... Positional arguments for the description. 382 /// 383 /// \return The generated error. 384 kyua_error_t 385 kyua_generic_error_new(const char* message, ...) 386 { 387 char formatted[1024]; 388 va_list ap; 389 390 va_start(ap, message); 391 (void)vsnprintf(formatted, sizeof(formatted), message, ap); 392 va_end(ap); 393 394 return kyua_error_new(kyua_generic_error_type, formatted, sizeof(formatted), 395 generic_format); 396 } 397 398 399 /// Name of a libc type. 400 const char* const kyua_libc_error_type = "libc"; 401 402 403 /// Representation of a libc error. 404 struct libc_error_data { 405 /// Value of the errno captured during the error creation. 406 int original_errno; 407 408 /// Explanation of the problem that lead to the error. 409 char description[4096]; 410 }; 411 /// Shorthand for a libc_error_data structure. 412 typedef struct libc_error_data libc_error_data_t; 413 414 415 /// Generates a user-friendly representation of the error. 416 /// 417 /// \pre The error must be set. 418 /// 419 /// \param error Error for which to generate a message. 420 /// \param output_buffer Buffer to hold the generated message. 421 /// \param output_size Length of output_buffer. 422 /// 423 /// \return The number of bytes written to output_buffer, or a negative value if 424 /// there was an error. 425 static int 426 libc_format(const kyua_error_t error, char* const output_buffer, 427 const size_t output_size) 428 { 429 assert(kyua_error_is_type(error, kyua_libc_error_type)); 430 431 const libc_error_data_t* data = kyua_error_data(error); 432 return snprintf(output_buffer, output_size, "%s: %s", data->description, 433 strerror(data->original_errno)); 434 } 435 436 437 /// Constructs a new libc error. 438 /// 439 /// \param original_errno libc error code for this error. 440 /// \param description Textual description of the problem. 441 /// \param ... Positional arguments for the description. 442 /// 443 /// \return The generated error. 444 kyua_error_t 445 kyua_libc_error_new(const int original_errno, const char* description, ...) 446 { 447 va_list ap; 448 449 const size_t data_size = sizeof(libc_error_data_t); 450 libc_error_data_t* data = (libc_error_data_t*)malloc(data_size); 451 if (data == NULL) 452 return kyua_oom_error_new(); 453 454 data->original_errno = original_errno; 455 va_start(ap, description); 456 (void)vsnprintf(data->description, sizeof(data->description), 457 description, ap); 458 va_end(ap); 459 460 return kyua_error_new(kyua_libc_error_type, data, data_size, libc_format); 461 } 462 463 464 /// Extracts the original errno of a libc error. 465 /// 466 /// \pre error must have been constructed by kyua_libc_error_new. 467 /// 468 /// \param error The error object to access. 469 /// 470 /// \return The libc error code. 471 int 472 kyua_libc_error_errno(const kyua_error_t error) 473 { 474 assert(kyua_error_is_type(error, kyua_libc_error_type)); 475 476 const struct libc_error_data* data = kyua_error_data(error); 477 return data->original_errno; 478 } 479 480 481 /// Name of an OOM type. 482 const char* const kyua_oom_error_type = "oom"; 483 484 485 /// Data of an out of memory error. 486 /// 487 /// All error types are allocated in dynamic memory. However, doing so for 488 /// an out of memory error is not possible because, when we are out of 489 /// memory, we probably cannot allocate more memory to generate an error. 490 /// Therefore, we just keep a single static instance of the out of memory 491 /// error around all the time. 492 static struct kyua_error oom_error; 493 494 495 /// Generates a user-friendly representation of the error. 496 /// 497 /// \pre The error must be set. 498 /// 499 /// \param error Error for which to generate a message. 500 /// \param output_buffer Buffer to hold the generated message. 501 /// \param output_size Length of output_buffer. 502 /// 503 /// \return The number of bytes written to output_buffer, or a negative value if 504 /// there was an error. 505 static int 506 oom_format(const kyua_error_t error, char* const output_buffer, 507 const size_t output_size) 508 { 509 assert(kyua_error_is_type(error, kyua_oom_error_type)); 510 511 return snprintf(output_buffer, output_size, "Not enough memory"); 512 } 513 514 515 /// Constructs a new out-of-memory error. 516 /// 517 /// This will always succeed because we just return a reference to the 518 /// statically-allocated oom_error. 519 /// 520 /// \return An error representing an out of memory condition. 521 kyua_error_t 522 kyua_oom_error_new(void) 523 { 524 // This is idempotent; no need to ensure that we call it only once. 525 #if defined(__minix) && !defined(NDEBUG) 526 const bool ok = 527 #endif /* defined(__minix) && !defined(NDEBUG) */ 528 error_init(&oom_error, kyua_oom_error_type, NULL, 0, oom_format); 529 assert(ok); 530 531 return &oom_error; 532 } 533 534 535 /// Name of an usage error type. 536 const char* const kyua_usage_error_type = "usage"; 537 538 539 /// Generates a user-friendly representation of the error. 540 /// 541 /// \pre The error must be set. 542 /// 543 /// \param error Error for which to generate a message. 544 /// \param output_buffer Buffer to hold the generated message. 545 /// \param output_size Length of output_buffer. 546 /// 547 /// \return The number of bytes written to output_buffer, or a negative value if 548 /// there was an error. 549 static int 550 usage_format(const kyua_error_t error, char* const output_buffer, 551 const size_t output_size) 552 { 553 assert(kyua_error_is_type(error, kyua_usage_error_type)); 554 555 const char* message = kyua_error_data(error); 556 return snprintf(output_buffer, output_size, "%s", message); 557 } 558 559 560 /// Constructs a new usage error. 561 /// 562 /// \param message Textual description of the problem. 563 /// \param ... Positional arguments for the description. 564 /// 565 /// \return The generated error. 566 kyua_error_t 567 kyua_usage_error_new(const char* message, ...) 568 { 569 char formatted[1024]; 570 va_list ap; 571 572 va_start(ap, message); 573 (void)vsnprintf(formatted, sizeof(formatted), message, ap); 574 va_end(ap); 575 576 return kyua_error_new(kyua_usage_error_type, formatted, sizeof(formatted), 577 usage_format); 578 } 579