error.c revision 240116
1/* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2008 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 37#include "detail/sanity.h" 38 39/* Theoretically, there can only be a single error intance at any given 40 * point in time, because errors are raised at one point and must be 41 * handled immediately. If another error has to be raised during the 42 * handling process, something else has to be done with the previous 43 * error. 44 * 45 * This is per-thread information and will break threaded tests, but we 46 * currently do not have any threading support; therefore, this is fine. */ 47static bool error_on_flight = false; 48 49/* --------------------------------------------------------------------- 50 * Auxiliary functions. 51 * --------------------------------------------------------------------- */ 52 53static 54void 55error_format(const atf_error_t err, char *buf, size_t buflen) 56{ 57 PRE(err != NULL); 58 snprintf(buf, buflen, "Error '%s'", err->m_type); 59} 60 61static 62bool 63error_init(atf_error_t err, const char *type, void *data, size_t datalen, 64 void (*format)(const atf_error_t, char *, size_t)) 65{ 66 bool ok; 67 68 PRE(data != NULL || datalen == 0); 69 PRE(datalen != 0 || data == NULL); 70 71 err->m_free = false; 72 err->m_type = type; 73 err->m_format = (format == NULL) ? error_format : format; 74 75 ok = true; 76 if (data == NULL) { 77 err->m_data = NULL; 78 } else { 79 err->m_data = malloc(datalen); 80 if (err->m_data == NULL) { 81 ok = false; 82 } else 83 memcpy(err->m_data, data, datalen); 84 } 85 86 return ok; 87} 88 89/* --------------------------------------------------------------------- 90 * The "atf_error" type. 91 * --------------------------------------------------------------------- */ 92 93atf_error_t 94atf_error_new(const char *type, void *data, size_t datalen, 95 void (*format)(const atf_error_t, char *, size_t)) 96{ 97 atf_error_t err; 98 99 PRE(!error_on_flight); 100 PRE(data != NULL || datalen == 0); 101 PRE(datalen != 0 || data == NULL); 102 103 err = malloc(sizeof(*err)); 104 if (err == NULL) 105 err = atf_no_memory_error(); 106 else { 107 if (!error_init(err, type, data, datalen, format)) { 108 free(err); 109 err = atf_no_memory_error(); 110 } else { 111 err->m_free = true; 112 error_on_flight = true; 113 } 114 } 115 116 INV(err != NULL); 117 POST(error_on_flight); 118 return err; 119} 120 121void 122atf_error_free(atf_error_t err) 123{ 124 bool freeit; 125 126 PRE(error_on_flight); 127 PRE(err != NULL); 128 129 freeit = err->m_free; 130 131 if (err->m_data != NULL) 132 free(err->m_data); 133 134 if (freeit) 135 free(err); 136 137 error_on_flight = false; 138} 139 140atf_error_t 141atf_no_error(void) 142{ 143 return NULL; 144} 145 146bool 147atf_is_error(const atf_error_t err) 148{ 149 return err != NULL; 150} 151 152bool 153atf_error_is(const atf_error_t err, const char *type) 154{ 155 PRE(err != NULL); 156 157 return strcmp(err->m_type, type) == 0; 158} 159 160const void * 161atf_error_data(const atf_error_t err) 162{ 163 PRE(err != NULL); 164 165 return err->m_data; 166} 167 168void 169atf_error_format(const atf_error_t err, char *buf, size_t buflen) 170{ 171 PRE(err != NULL); 172 err->m_format(err, buf, buflen); 173} 174 175/* --------------------------------------------------------------------- 176 * Common error types. 177 * --------------------------------------------------------------------- */ 178 179/* 180 * The "libc" error. 181 */ 182 183struct atf_libc_error_data { 184 int m_errno; 185 char m_what[4096]; 186}; 187typedef struct atf_libc_error_data atf_libc_error_data_t; 188 189static 190void 191libc_format(const atf_error_t err, char *buf, size_t buflen) 192{ 193 const atf_libc_error_data_t *data; 194 195 PRE(atf_error_is(err, "libc")); 196 197 data = atf_error_data(err); 198 snprintf(buf, buflen, "%s: %s", data->m_what, strerror(data->m_errno)); 199} 200 201atf_error_t 202atf_libc_error(int syserrno, const char *fmt, ...) 203{ 204 atf_error_t err; 205 atf_libc_error_data_t data; 206 va_list ap; 207 208 data.m_errno = syserrno; 209 va_start(ap, fmt); 210 vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap); 211 va_end(ap); 212 213 err = atf_error_new("libc", &data, sizeof(data), libc_format); 214 215 return err; 216} 217 218int 219atf_libc_error_code(const atf_error_t err) 220{ 221 const struct atf_libc_error_data *data; 222 223 PRE(atf_error_is(err, "libc")); 224 225 data = atf_error_data(err); 226 227 return data->m_errno; 228} 229 230const char * 231atf_libc_error_msg(const atf_error_t err) 232{ 233 const struct atf_libc_error_data *data; 234 235 PRE(atf_error_is(err, "libc")); 236 237 data = atf_error_data(err); 238 239 return data->m_what; 240} 241 242/* 243 * The "no_memory" error. 244 */ 245 246static struct atf_error no_memory_error; 247 248static 249void 250no_memory_format(const atf_error_t err, char *buf, size_t buflen) 251{ 252 PRE(atf_error_is(err, "no_memory")); 253 254 snprintf(buf, buflen, "Not enough memory"); 255} 256 257atf_error_t 258atf_no_memory_error(void) 259{ 260 PRE(!error_on_flight); 261 262 error_init(&no_memory_error, "no_memory", NULL, 0, 263 no_memory_format); 264 265 error_on_flight = true; 266 return &no_memory_error; 267} 268