Home | History | Annotate | Line # | Download | only in dist
      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     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.
    534 const 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.
    547 static int
    548 usage_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.
    564 kyua_error_t
    565 kyua_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