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