1273929Sjmmv/* Copyright (c) 2008 The NetBSD Foundation, Inc. 2240116Smarcel * All rights reserved. 3240116Smarcel * 4240116Smarcel * Redistribution and use in source and binary forms, with or without 5240116Smarcel * modification, are permitted provided that the following conditions 6240116Smarcel * are met: 7240116Smarcel * 1. Redistributions of source code must retain the above copyright 8240116Smarcel * notice, this list of conditions and the following disclaimer. 9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 10240116Smarcel * notice, this list of conditions and the following disclaimer in the 11240116Smarcel * documentation and/or other materials provided with the distribution. 12240116Smarcel * 13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24273929Sjmmv * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 25240116Smarcel 26273929Sjmmv#include "atf-c/error.h" 27273929Sjmmv 28240116Smarcel#include <stdarg.h> 29240116Smarcel#include <stdio.h> 30240116Smarcel#include <stdlib.h> 31240116Smarcel#include <string.h> 32240116Smarcel 33273929Sjmmv#include "atf-c/detail/sanity.h" 34240116Smarcel 35240116Smarcel/* Theoretically, there can only be a single error intance at any given 36240116Smarcel * point in time, because errors are raised at one point and must be 37240116Smarcel * handled immediately. If another error has to be raised during the 38240116Smarcel * handling process, something else has to be done with the previous 39240116Smarcel * error. 40240116Smarcel * 41240116Smarcel * This is per-thread information and will break threaded tests, but we 42240116Smarcel * currently do not have any threading support; therefore, this is fine. */ 43240116Smarcelstatic bool error_on_flight = false; 44240116Smarcel 45240116Smarcel/* --------------------------------------------------------------------- 46240116Smarcel * Auxiliary functions. 47240116Smarcel * --------------------------------------------------------------------- */ 48240116Smarcel 49240116Smarcelstatic 50240116Smarcelvoid 51240116Smarcelerror_format(const atf_error_t err, char *buf, size_t buflen) 52240116Smarcel{ 53240116Smarcel PRE(err != NULL); 54240116Smarcel snprintf(buf, buflen, "Error '%s'", err->m_type); 55240116Smarcel} 56240116Smarcel 57240116Smarcelstatic 58240116Smarcelbool 59240116Smarcelerror_init(atf_error_t err, const char *type, void *data, size_t datalen, 60240116Smarcel void (*format)(const atf_error_t, char *, size_t)) 61240116Smarcel{ 62240116Smarcel bool ok; 63240116Smarcel 64240116Smarcel PRE(data != NULL || datalen == 0); 65240116Smarcel PRE(datalen != 0 || data == NULL); 66240116Smarcel 67240116Smarcel err->m_free = false; 68240116Smarcel err->m_type = type; 69240116Smarcel err->m_format = (format == NULL) ? error_format : format; 70240116Smarcel 71240116Smarcel ok = true; 72240116Smarcel if (data == NULL) { 73240116Smarcel err->m_data = NULL; 74240116Smarcel } else { 75240116Smarcel err->m_data = malloc(datalen); 76240116Smarcel if (err->m_data == NULL) { 77240116Smarcel ok = false; 78240116Smarcel } else 79240116Smarcel memcpy(err->m_data, data, datalen); 80240116Smarcel } 81240116Smarcel 82240116Smarcel return ok; 83240116Smarcel} 84240116Smarcel 85240116Smarcel/* --------------------------------------------------------------------- 86240116Smarcel * The "atf_error" type. 87240116Smarcel * --------------------------------------------------------------------- */ 88240116Smarcel 89240116Smarcelatf_error_t 90240116Smarcelatf_error_new(const char *type, void *data, size_t datalen, 91240116Smarcel void (*format)(const atf_error_t, char *, size_t)) 92240116Smarcel{ 93240116Smarcel atf_error_t err; 94240116Smarcel 95240116Smarcel PRE(!error_on_flight); 96240116Smarcel PRE(data != NULL || datalen == 0); 97240116Smarcel PRE(datalen != 0 || data == NULL); 98240116Smarcel 99240116Smarcel err = malloc(sizeof(*err)); 100240116Smarcel if (err == NULL) 101240116Smarcel err = atf_no_memory_error(); 102240116Smarcel else { 103240116Smarcel if (!error_init(err, type, data, datalen, format)) { 104240116Smarcel free(err); 105240116Smarcel err = atf_no_memory_error(); 106240116Smarcel } else { 107240116Smarcel err->m_free = true; 108240116Smarcel error_on_flight = true; 109240116Smarcel } 110240116Smarcel } 111240116Smarcel 112240116Smarcel INV(err != NULL); 113240116Smarcel POST(error_on_flight); 114240116Smarcel return err; 115240116Smarcel} 116240116Smarcel 117240116Smarcelvoid 118240116Smarcelatf_error_free(atf_error_t err) 119240116Smarcel{ 120240116Smarcel bool freeit; 121240116Smarcel 122240116Smarcel PRE(error_on_flight); 123240116Smarcel PRE(err != NULL); 124240116Smarcel 125240116Smarcel freeit = err->m_free; 126240116Smarcel 127240116Smarcel if (err->m_data != NULL) 128240116Smarcel free(err->m_data); 129240116Smarcel 130240116Smarcel if (freeit) 131240116Smarcel free(err); 132240116Smarcel 133240116Smarcel error_on_flight = false; 134240116Smarcel} 135240116Smarcel 136240116Smarcelatf_error_t 137240116Smarcelatf_no_error(void) 138240116Smarcel{ 139240116Smarcel return NULL; 140240116Smarcel} 141240116Smarcel 142240116Smarcelbool 143240116Smarcelatf_is_error(const atf_error_t err) 144240116Smarcel{ 145240116Smarcel return err != NULL; 146240116Smarcel} 147240116Smarcel 148240116Smarcelbool 149240116Smarcelatf_error_is(const atf_error_t err, const char *type) 150240116Smarcel{ 151240116Smarcel PRE(err != NULL); 152240116Smarcel 153240116Smarcel return strcmp(err->m_type, type) == 0; 154240116Smarcel} 155240116Smarcel 156240116Smarcelconst void * 157240116Smarcelatf_error_data(const atf_error_t err) 158240116Smarcel{ 159240116Smarcel PRE(err != NULL); 160240116Smarcel 161240116Smarcel return err->m_data; 162240116Smarcel} 163240116Smarcel 164240116Smarcelvoid 165240116Smarcelatf_error_format(const atf_error_t err, char *buf, size_t buflen) 166240116Smarcel{ 167240116Smarcel PRE(err != NULL); 168240116Smarcel err->m_format(err, buf, buflen); 169240116Smarcel} 170240116Smarcel 171240116Smarcel/* --------------------------------------------------------------------- 172240116Smarcel * Common error types. 173240116Smarcel * --------------------------------------------------------------------- */ 174240116Smarcel 175240116Smarcel/* 176240116Smarcel * The "libc" error. 177240116Smarcel */ 178240116Smarcel 179240116Smarcelstruct atf_libc_error_data { 180240116Smarcel int m_errno; 181240116Smarcel char m_what[4096]; 182240116Smarcel}; 183240116Smarceltypedef struct atf_libc_error_data atf_libc_error_data_t; 184240116Smarcel 185240116Smarcelstatic 186240116Smarcelvoid 187240116Smarcellibc_format(const atf_error_t err, char *buf, size_t buflen) 188240116Smarcel{ 189240116Smarcel const atf_libc_error_data_t *data; 190240116Smarcel 191240116Smarcel PRE(atf_error_is(err, "libc")); 192240116Smarcel 193240116Smarcel data = atf_error_data(err); 194240116Smarcel snprintf(buf, buflen, "%s: %s", data->m_what, strerror(data->m_errno)); 195240116Smarcel} 196240116Smarcel 197240116Smarcelatf_error_t 198240116Smarcelatf_libc_error(int syserrno, const char *fmt, ...) 199240116Smarcel{ 200240116Smarcel atf_error_t err; 201240116Smarcel atf_libc_error_data_t data; 202240116Smarcel va_list ap; 203240116Smarcel 204240116Smarcel data.m_errno = syserrno; 205240116Smarcel va_start(ap, fmt); 206240116Smarcel vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap); 207240116Smarcel va_end(ap); 208240116Smarcel 209240116Smarcel err = atf_error_new("libc", &data, sizeof(data), libc_format); 210240116Smarcel 211240116Smarcel return err; 212240116Smarcel} 213240116Smarcel 214240116Smarcelint 215240116Smarcelatf_libc_error_code(const atf_error_t err) 216240116Smarcel{ 217240116Smarcel const struct atf_libc_error_data *data; 218240116Smarcel 219240116Smarcel PRE(atf_error_is(err, "libc")); 220240116Smarcel 221240116Smarcel data = atf_error_data(err); 222240116Smarcel 223240116Smarcel return data->m_errno; 224240116Smarcel} 225240116Smarcel 226240116Smarcelconst char * 227240116Smarcelatf_libc_error_msg(const atf_error_t err) 228240116Smarcel{ 229240116Smarcel const struct atf_libc_error_data *data; 230240116Smarcel 231240116Smarcel PRE(atf_error_is(err, "libc")); 232240116Smarcel 233240116Smarcel data = atf_error_data(err); 234240116Smarcel 235240116Smarcel return data->m_what; 236240116Smarcel} 237240116Smarcel 238240116Smarcel/* 239240116Smarcel * The "no_memory" error. 240240116Smarcel */ 241240116Smarcel 242240116Smarcelstatic struct atf_error no_memory_error; 243240116Smarcel 244240116Smarcelstatic 245240116Smarcelvoid 246240116Smarcelno_memory_format(const atf_error_t err, char *buf, size_t buflen) 247240116Smarcel{ 248240116Smarcel PRE(atf_error_is(err, "no_memory")); 249240116Smarcel 250240116Smarcel snprintf(buf, buflen, "Not enough memory"); 251240116Smarcel} 252240116Smarcel 253240116Smarcelatf_error_t 254240116Smarcelatf_no_memory_error(void) 255240116Smarcel{ 256240116Smarcel PRE(!error_on_flight); 257240116Smarcel 258240116Smarcel error_init(&no_memory_error, "no_memory", NULL, 0, 259240116Smarcel no_memory_format); 260240116Smarcel 261240116Smarcel error_on_flight = true; 262240116Smarcel return &no_memory_error; 263240116Smarcel} 264