1 /* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2008, 2009, 2010 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 err->m_free = false; 71 err->m_type = type; 72 err->m_format = (format == NULL) ? error_format : format; 73 74 ok = true; 75 if (data == NULL) { 76 err->m_data = NULL; 77 } else { 78 err->m_data = malloc(datalen); 79 if (err->m_data == NULL) { 80 ok = false; 81 } else 82 memcpy(err->m_data, data, datalen); 83 } 84 85 return ok; 86 } 87 88 /* --------------------------------------------------------------------- 89 * The "atf_error" type. 90 * --------------------------------------------------------------------- */ 91 92 atf_error_t 93 atf_error_new(const char *type, void *data, size_t datalen, 94 void (*format)(const atf_error_t, char *, size_t)) 95 { 96 atf_error_t err; 97 98 PRE(!error_on_flight); 99 PRE(data != NULL || datalen == 0); 100 PRE(datalen != 0 || data == NULL); 101 102 err = malloc(sizeof(*err)); 103 if (err == NULL) 104 err = atf_no_memory_error(); 105 else { 106 if (!error_init(err, type, data, datalen, format)) { 107 free(err); 108 err = atf_no_memory_error(); 109 } else { 110 err->m_free = true; 111 error_on_flight = true; 112 } 113 } 114 115 INV(err != NULL); 116 POST(error_on_flight); 117 return err; 118 } 119 120 void 121 atf_error_free(atf_error_t err) 122 { 123 bool freeit; 124 125 PRE(error_on_flight); 126 PRE(err != NULL); 127 128 freeit = err->m_free; 129 130 if (err->m_data != NULL) 131 free(err->m_data); 132 133 if (freeit) 134 free(err); 135 136 error_on_flight = false; 137 } 138 139 atf_error_t 140 atf_no_error(void) 141 { 142 return NULL; 143 } 144 145 bool 146 atf_is_error(const atf_error_t err) 147 { 148 return err != NULL; 149 } 150 151 bool 152 atf_error_is(const atf_error_t err, const char *type) 153 { 154 PRE(err != NULL); 155 156 return strcmp(err->m_type, type) == 0; 157 } 158 159 const void * 160 atf_error_data(const atf_error_t err) 161 { 162 PRE(err != NULL); 163 164 return err->m_data; 165 } 166 167 void 168 atf_error_format(const atf_error_t err, char *buf, size_t buflen) 169 { 170 PRE(err != NULL); 171 err->m_format(err, buf, buflen); 172 } 173 174 /* --------------------------------------------------------------------- 175 * Common error types. 176 * --------------------------------------------------------------------- */ 177 178 /* 179 * The "libc" error. 180 */ 181 182 struct atf_libc_error_data { 183 int m_errno; 184 char m_what[4096]; 185 }; 186 typedef struct atf_libc_error_data atf_libc_error_data_t; 187 188 static 189 void 190 libc_format(const atf_error_t err, char *buf, size_t buflen) 191 { 192 const atf_libc_error_data_t *data; 193 194 PRE(atf_error_is(err, "libc")); 195 196 data = atf_error_data(err); 197 snprintf(buf, buflen, "%s: %s", data->m_what, strerror(data->m_errno)); 198 } 199 200 atf_error_t 201 atf_libc_error(int syserrno, const char *fmt, ...) 202 { 203 atf_error_t err; 204 atf_libc_error_data_t data; 205 va_list ap; 206 207 data.m_errno = syserrno; 208 va_start(ap, fmt); 209 vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap); 210 va_end(ap); 211 212 err = atf_error_new("libc", &data, sizeof(data), libc_format); 213 214 return err; 215 } 216 217 int 218 atf_libc_error_code(const atf_error_t err) 219 { 220 const struct atf_libc_error_data *data; 221 222 PRE(atf_error_is(err, "libc")); 223 224 data = atf_error_data(err); 225 226 return data->m_errno; 227 } 228 229 const char * 230 atf_libc_error_msg(const atf_error_t err) 231 { 232 const struct atf_libc_error_data *data; 233 234 PRE(atf_error_is(err, "libc")); 235 236 data = atf_error_data(err); 237 238 return data->m_what; 239 } 240 241 /* 242 * The "no_memory" error. 243 */ 244 245 static struct atf_error no_memory_error; 246 247 static 248 void 249 no_memory_format(const atf_error_t err, char *buf, size_t buflen) 250 { 251 PRE(atf_error_is(err, "no_memory")); 252 253 snprintf(buf, buflen, "Not enough memory"); 254 } 255 256 atf_error_t 257 atf_no_memory_error(void) 258 { 259 PRE(!error_on_flight); 260 261 error_init(&no_memory_error, "no_memory", NULL, 0, 262 no_memory_format); 263 264 error_on_flight = true; 265 return &no_memory_error; 266 } 267