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. */ 47 static bool error_on_flight = false; 48 49 /* --------------------------------------------------------------------- 50 * Auxiliary functions. 51 * --------------------------------------------------------------------- */ 52 53 static 54 void 55 error_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 61 static 62 bool 63 error_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 93 atf_error_t 94 atf_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 121 void 122 atf_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 140 atf_error_t 141 atf_no_error(void) 142 { 143 return NULL; 144 } 145 146 bool 147 atf_is_error(const atf_error_t err) 148 { 149 return err != NULL; 150 } 151 152 bool 153 atf_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 160 const void * 161 atf_error_data(const atf_error_t err) 162 { 163 PRE(err != NULL); 164 165 return err->m_data; 166 } 167 168 void 169 atf_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 183 struct atf_libc_error_data { 184 int m_errno; 185 char m_what[4096]; 186 }; 187 typedef struct atf_libc_error_data atf_libc_error_data_t; 188 189 static 190 void 191 libc_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 201 atf_error_t 202 atf_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 218 int 219 atf_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 230 const char * 231 atf_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 246 static struct atf_error no_memory_error; 247 248 static 249 void 250 no_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 257 atf_error_t 258 atf_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