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 instance 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. */ 43 static bool error_on_flight = false; 44 45 /* --------------------------------------------------------------------- 46 * Auxiliary functions. 47 * --------------------------------------------------------------------- */ 48 49 static 50 void 51 error_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 57 static 58 bool 59 error_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 89 atf_error_t 90 atf_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 117 void 118 atf_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 free(err->m_data); 128 err->m_data = NULL; 129 130 if (freeit) { 131 free(err); 132 err = NULL; 133 } 134 135 error_on_flight = false; 136 } 137 138 atf_error_t 139 atf_no_error(void) 140 { 141 return NULL; 142 } 143 144 bool 145 atf_is_error(const atf_error_t err) 146 { 147 return err != NULL; 148 } 149 150 bool 151 atf_error_is(const atf_error_t err, const char *type) 152 { 153 PRE(err != NULL); 154 155 return strcmp(err->m_type, type) == 0; 156 } 157 158 const void * 159 atf_error_data(const atf_error_t err) 160 { 161 PRE(err != NULL); 162 163 return err->m_data; 164 } 165 166 void 167 atf_error_format(const atf_error_t err, char *buf, size_t buflen) 168 { 169 PRE(err != NULL); 170 err->m_format(err, buf, buflen); 171 } 172 173 /* --------------------------------------------------------------------- 174 * Common error types. 175 * --------------------------------------------------------------------- */ 176 177 /* 178 * The "libc" error. 179 */ 180 181 struct atf_libc_error_data { 182 int m_errno; 183 char m_what[4096]; 184 }; 185 typedef struct atf_libc_error_data atf_libc_error_data_t; 186 187 static 188 void 189 libc_format(const atf_error_t err, char *buf, size_t buflen) 190 { 191 const atf_libc_error_data_t *data; 192 193 PRE(atf_error_is(err, "libc")); 194 195 data = atf_error_data(err); 196 snprintf(buf, buflen, "%s: %s", data->m_what, strerror(data->m_errno)); 197 } 198 199 atf_error_t 200 atf_libc_error(int syserrno, const char *fmt, ...) 201 { 202 atf_error_t err; 203 atf_libc_error_data_t data; 204 va_list ap; 205 206 data.m_errno = syserrno; 207 va_start(ap, fmt); 208 vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap); 209 va_end(ap); 210 211 err = atf_error_new("libc", &data, sizeof(data), libc_format); 212 213 return err; 214 } 215 216 int 217 atf_libc_error_code(const atf_error_t err) 218 { 219 const struct atf_libc_error_data *data; 220 221 PRE(atf_error_is(err, "libc")); 222 223 data = atf_error_data(err); 224 225 return data->m_errno; 226 } 227 228 const char * 229 atf_libc_error_msg(const atf_error_t err) 230 { 231 const struct atf_libc_error_data *data; 232 233 PRE(atf_error_is(err, "libc")); 234 235 data = atf_error_data(err); 236 237 return data->m_what; 238 } 239 240 /* 241 * The "no_memory" error. 242 */ 243 244 static struct atf_error no_memory_error; 245 246 static 247 void 248 no_memory_format(const atf_error_t err, char *buf, size_t buflen) 249 { 250 PRE(atf_error_is(err, "no_memory")); 251 252 snprintf(buf, buflen, "Not enough memory"); 253 } 254 255 atf_error_t 256 atf_no_memory_error(void) 257 { 258 PRE(!error_on_flight); 259 260 error_init(&no_memory_error, "no_memory", NULL, 0, 261 no_memory_format); 262 263 error_on_flight = true; 264 return &no_memory_error; 265 } 266