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. */ 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 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 136 atf_error_t 137 atf_no_error(void) 138 { 139 return NULL; 140 } 141 142 bool 143 atf_is_error(const atf_error_t err) 144 { 145 return err != NULL; 146 } 147 148 bool 149 atf_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 156 const void * 157 atf_error_data(const atf_error_t err) 158 { 159 PRE(err != NULL); 160 161 return err->m_data; 162 } 163 164 void 165 atf_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 179 struct atf_libc_error_data { 180 int m_errno; 181 char m_what[4096]; 182 }; 183 typedef struct atf_libc_error_data atf_libc_error_data_t; 184 185 static 186 void 187 libc_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 197 atf_error_t 198 atf_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 214 int 215 atf_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 226 const char * 227 atf_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 242 static struct atf_error no_memory_error; 243 244 static 245 void 246 no_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 253 atf_error_t 254 atf_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