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