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