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. 44static int 45generic_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. 65static bool 66error_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. 110kyua_error_t 111kyua_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. 138void 139kyua_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. 166kyua_error_t 167kyua_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. 182kyua_error_t 183kyua_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. 194bool 195kyua_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. 209bool 210kyua_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. 226const void* 227kyua_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. 248int 249kyua_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. 267static int 268format_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. 297void 298kyua_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. 319void 320kyua_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. 339void 340kyua_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. 354const 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. 367static int 368generic_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. 384kyua_error_t 385kyua_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. 400const char* const kyua_libc_error_type = "libc"; 401 402 403/// Representation of a libc error. 404struct 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. 412typedef 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. 425static int 426libc_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. 444kyua_error_t 445kyua_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. 471int 472kyua_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. 482const 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. 492static 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. 505static int 506oom_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. 521kyua_error_t 522kyua_oom_error_new(void) 523{ 524 // This is idempotent; no need to ensure that we call it only once. 525 const bool ok = error_init(&oom_error, kyua_oom_error_type, NULL, 0, 526 oom_format); 527 assert(ok); 528 529 return &oom_error; 530} 531 532 533/// Name of an usage error type. 534const char* const kyua_usage_error_type = "usage"; 535 536 537/// Generates a user-friendly representation of the error. 538/// 539/// \pre The error must be set. 540/// 541/// \param error Error for which to generate a message. 542/// \param output_buffer Buffer to hold the generated message. 543/// \param output_size Length of output_buffer. 544/// 545/// \return The number of bytes written to output_buffer, or a negative value if 546/// there was an error. 547static int 548usage_format(const kyua_error_t error, char* const output_buffer, 549 const size_t output_size) 550{ 551 assert(kyua_error_is_type(error, kyua_usage_error_type)); 552 553 const char* message = kyua_error_data(error); 554 return snprintf(output_buffer, output_size, "%s", message); 555} 556 557 558/// Constructs a new usage error. 559/// 560/// \param message Textual description of the problem. 561/// \param ... Positional arguments for the description. 562/// 563/// \return The generated error. 564kyua_error_t 565kyua_usage_error_new(const char* message, ...) 566{ 567 char formatted[1024]; 568 va_list ap; 569 570 va_start(ap, message); 571 (void)vsnprintf(formatted, sizeof(formatted), message, ap); 572 va_end(ap); 573 574 return kyua_error_new(kyua_usage_error_type, formatted, sizeof(formatted), 575 usage_format); 576} 577