Home | History | Annotate | Line # | Download | only in atf-c
error.c revision 1.1.1.2
      1 /*
      2  * Automated Testing Framework (atf)
      3  *
      4  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
     17  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
     25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <stdarg.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 
     35 #include "atf-c/error.h"
     36 #include "atf-c/sanity.h"
     37 
     38 /* Theoretically, there can only be a single error intance at any given
     39  * point in time, because errors are raised at one point and must be
     40  * handled immediately.  If another error has to be raised during the
     41  * handling process, something else has to be done with the previous
     42  * error.
     43  *
     44  * This is per-thread information and will break threaded tests, but we
     45  * currently do not have any threading support; therefore, this is fine. */
     46 static bool error_on_flight = false;
     47 
     48 /* ---------------------------------------------------------------------
     49  * Auxiliary functions.
     50  * --------------------------------------------------------------------- */
     51 
     52 static
     53 void
     54 error_format(const atf_error_t err, char *buf, size_t buflen)
     55 {
     56     PRE(err != NULL);
     57     snprintf(buf, buflen, "Error '%s'", err->m_type);
     58 }
     59 
     60 static
     61 bool
     62 error_init(atf_error_t err, const char *type, void *data, size_t datalen,
     63            void (*format)(const atf_error_t, char *, size_t))
     64 {
     65     bool ok;
     66 
     67     PRE(data != NULL || datalen == 0);
     68     PRE(datalen != 0 || data == NULL);
     69 
     70     atf_object_init(&err->m_object);
     71 
     72     err->m_free = false;
     73     err->m_type = type;
     74     err->m_format = (format == NULL) ? error_format : format;
     75 
     76     ok = true;
     77     if (data == NULL) {
     78         err->m_data = NULL;
     79     } else {
     80         err->m_data = malloc(datalen);
     81         if (err->m_data == NULL) {
     82             atf_object_fini(&err->m_object);
     83             ok = false;
     84         } else
     85             memcpy(err->m_data, data, datalen);
     86     }
     87 
     88     return ok;
     89 }
     90 
     91 /* ---------------------------------------------------------------------
     92  * The "atf_error" type.
     93  * --------------------------------------------------------------------- */
     94 
     95 atf_error_t
     96 atf_error_new(const char *type, void *data, size_t datalen,
     97               void (*format)(const atf_error_t, char *, size_t))
     98 {
     99     atf_error_t err;
    100 
    101     PRE(!error_on_flight);
    102     PRE(data != NULL || datalen == 0);
    103     PRE(datalen != 0 || data == NULL);
    104 
    105     err = malloc(sizeof(*err));
    106     if (err == NULL)
    107         err = atf_no_memory_error();
    108     else {
    109         if (!error_init(err, type, data, datalen, format)) {
    110             free(err);
    111             err = atf_no_memory_error();
    112         } else {
    113             err->m_free = true;
    114             error_on_flight = true;
    115         }
    116     }
    117 
    118     INV(err != NULL);
    119     POST(error_on_flight);
    120     return err;
    121 }
    122 
    123 void
    124 atf_error_free(atf_error_t err)
    125 {
    126     bool freeit;
    127 
    128     PRE(error_on_flight);
    129     PRE(err != NULL);
    130 
    131     freeit = err->m_free;
    132 
    133     if (err->m_data != NULL)
    134         free(err->m_data);
    135 
    136     atf_object_fini(&err->m_object);
    137 
    138     if (freeit)
    139         free(err);
    140 
    141     error_on_flight = false;
    142 }
    143 
    144 atf_error_t
    145 atf_no_error(void)
    146 {
    147     return NULL;
    148 }
    149 
    150 bool
    151 atf_is_error(const atf_error_t err)
    152 {
    153     return err != NULL;
    154 }
    155 
    156 bool
    157 atf_error_is(const atf_error_t err, const char *type)
    158 {
    159     PRE(err != NULL);
    160 
    161     return strcmp(err->m_type, type) == 0;
    162 }
    163 
    164 const void *
    165 atf_error_data(const atf_error_t err)
    166 {
    167     PRE(err != NULL);
    168 
    169     return err->m_data;
    170 }
    171 
    172 void
    173 atf_error_format(const atf_error_t err, char *buf, size_t buflen)
    174 {
    175     PRE(err != NULL);
    176     err->m_format(err, buf, buflen);
    177 }
    178 
    179 /* ---------------------------------------------------------------------
    180  * Common error types.
    181  * --------------------------------------------------------------------- */
    182 
    183 /*
    184  * The "libc" error.
    185  */
    186 
    187 struct atf_libc_error_data {
    188     int m_errno;
    189     char m_what[4096];
    190 };
    191 typedef struct atf_libc_error_data atf_libc_error_data_t;
    192 
    193 static
    194 void
    195 libc_format(const atf_error_t err, char *buf, size_t buflen)
    196 {
    197     const atf_libc_error_data_t *data;
    198 
    199     PRE(atf_error_is(err, "libc"));
    200 
    201     data = atf_error_data(err);
    202     snprintf(buf, buflen, "%s: %s", data->m_what, strerror(data->m_errno));
    203 }
    204 
    205 atf_error_t
    206 atf_libc_error(int syserrno, const char *fmt, ...)
    207 {
    208     atf_error_t err;
    209     atf_libc_error_data_t data;
    210     va_list ap;
    211 
    212     data.m_errno = syserrno;
    213     va_start(ap, fmt);
    214     vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap);
    215     va_end(ap);
    216 
    217     err = atf_error_new("libc", &data, sizeof(data), libc_format);
    218 
    219     return err;
    220 }
    221 
    222 int
    223 atf_libc_error_code(const atf_error_t err)
    224 {
    225     const struct atf_libc_error_data *data;
    226 
    227     PRE(atf_error_is(err, "libc"));
    228 
    229     data = atf_error_data(err);
    230 
    231     return data->m_errno;
    232 }
    233 
    234 const char *
    235 atf_libc_error_msg(const atf_error_t err)
    236 {
    237     const struct atf_libc_error_data *data;
    238 
    239     PRE(atf_error_is(err, "libc"));
    240 
    241     data = atf_error_data(err);
    242 
    243     return data->m_what;
    244 }
    245 
    246 /*
    247  * The "no_memory" error.
    248  */
    249 
    250 static struct atf_error no_memory_error;
    251 
    252 static
    253 void
    254 no_memory_format(const atf_error_t err, char *buf, size_t buflen)
    255 {
    256     PRE(atf_error_is(err, "no_memory"));
    257 
    258     snprintf(buf, buflen, "Not enough memory");
    259 }
    260 
    261 atf_error_t
    262 atf_no_memory_error(void)
    263 {
    264     PRE(!error_on_flight);
    265 
    266     error_init(&no_memory_error, "no_memory", NULL, 0,
    267                no_memory_format);
    268 
    269     error_on_flight = true;
    270     return &no_memory_error;
    271 }
    272