xref: /freebsd/contrib/atf/atf-c/error.c (revision 8f0ea33f2bbf3a6aa80235f0a02fa5f2780c2b17)
1*0677dfd1SJulio Merino /* Copyright (c) 2008 The NetBSD Foundation, Inc.
2c243e490SMarcel Moolenaar  * All rights reserved.
3c243e490SMarcel Moolenaar  *
4c243e490SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
5c243e490SMarcel Moolenaar  * modification, are permitted provided that the following conditions
6c243e490SMarcel Moolenaar  * are met:
7c243e490SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
8c243e490SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
9c243e490SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
10c243e490SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
11c243e490SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
12c243e490SMarcel Moolenaar  *
13c243e490SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14c243e490SMarcel Moolenaar  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15c243e490SMarcel Moolenaar  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16c243e490SMarcel Moolenaar  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17c243e490SMarcel Moolenaar  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18c243e490SMarcel Moolenaar  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c243e490SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20c243e490SMarcel Moolenaar  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21c243e490SMarcel Moolenaar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22c243e490SMarcel Moolenaar  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23c243e490SMarcel Moolenaar  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24*0677dfd1SJulio Merino  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25*0677dfd1SJulio Merino 
26*0677dfd1SJulio Merino #include "atf-c/error.h"
27c243e490SMarcel Moolenaar 
28c243e490SMarcel Moolenaar #include <stdarg.h>
29c243e490SMarcel Moolenaar #include <stdio.h>
30c243e490SMarcel Moolenaar #include <stdlib.h>
31c243e490SMarcel Moolenaar #include <string.h>
32c243e490SMarcel Moolenaar 
33*0677dfd1SJulio Merino #include "atf-c/detail/sanity.h"
34c243e490SMarcel Moolenaar 
35c243e490SMarcel Moolenaar /* Theoretically, there can only be a single error intance at any given
36c243e490SMarcel Moolenaar  * point in time, because errors are raised at one point and must be
37c243e490SMarcel Moolenaar  * handled immediately.  If another error has to be raised during the
38c243e490SMarcel Moolenaar  * handling process, something else has to be done with the previous
39c243e490SMarcel Moolenaar  * error.
40c243e490SMarcel Moolenaar  *
41c243e490SMarcel Moolenaar  * This is per-thread information and will break threaded tests, but we
42c243e490SMarcel Moolenaar  * currently do not have any threading support; therefore, this is fine. */
43c243e490SMarcel Moolenaar static bool error_on_flight = false;
44c243e490SMarcel Moolenaar 
45c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
46c243e490SMarcel Moolenaar  * Auxiliary functions.
47c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
48c243e490SMarcel Moolenaar 
49c243e490SMarcel Moolenaar static
50c243e490SMarcel Moolenaar void
error_format(const atf_error_t err,char * buf,size_t buflen)51c243e490SMarcel Moolenaar error_format(const atf_error_t err, char *buf, size_t buflen)
52c243e490SMarcel Moolenaar {
53c243e490SMarcel Moolenaar     PRE(err != NULL);
54c243e490SMarcel Moolenaar     snprintf(buf, buflen, "Error '%s'", err->m_type);
55c243e490SMarcel Moolenaar }
56c243e490SMarcel Moolenaar 
57c243e490SMarcel Moolenaar static
58c243e490SMarcel Moolenaar bool
error_init(atf_error_t err,const char * type,void * data,size_t datalen,void (* format)(const atf_error_t,char *,size_t))59c243e490SMarcel Moolenaar error_init(atf_error_t err, const char *type, void *data, size_t datalen,
60c243e490SMarcel Moolenaar            void (*format)(const atf_error_t, char *, size_t))
61c243e490SMarcel Moolenaar {
62c243e490SMarcel Moolenaar     bool ok;
63c243e490SMarcel Moolenaar 
64c243e490SMarcel Moolenaar     PRE(data != NULL || datalen == 0);
65c243e490SMarcel Moolenaar     PRE(datalen != 0 || data == NULL);
66c243e490SMarcel Moolenaar 
67c243e490SMarcel Moolenaar     err->m_free = false;
68c243e490SMarcel Moolenaar     err->m_type = type;
69c243e490SMarcel Moolenaar     err->m_format = (format == NULL) ? error_format : format;
70c243e490SMarcel Moolenaar 
71c243e490SMarcel Moolenaar     ok = true;
72c243e490SMarcel Moolenaar     if (data == NULL) {
73c243e490SMarcel Moolenaar         err->m_data = NULL;
74c243e490SMarcel Moolenaar     } else {
75c243e490SMarcel Moolenaar         err->m_data = malloc(datalen);
76c243e490SMarcel Moolenaar         if (err->m_data == NULL) {
77c243e490SMarcel Moolenaar             ok = false;
78c243e490SMarcel Moolenaar         } else
79c243e490SMarcel Moolenaar             memcpy(err->m_data, data, datalen);
80c243e490SMarcel Moolenaar     }
81c243e490SMarcel Moolenaar 
82c243e490SMarcel Moolenaar     return ok;
83c243e490SMarcel Moolenaar }
84c243e490SMarcel Moolenaar 
85c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
86c243e490SMarcel Moolenaar  * The "atf_error" type.
87c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
88c243e490SMarcel Moolenaar 
89c243e490SMarcel Moolenaar atf_error_t
atf_error_new(const char * type,void * data,size_t datalen,void (* format)(const atf_error_t,char *,size_t))90c243e490SMarcel Moolenaar atf_error_new(const char *type, void *data, size_t datalen,
91c243e490SMarcel Moolenaar               void (*format)(const atf_error_t, char *, size_t))
92c243e490SMarcel Moolenaar {
93c243e490SMarcel Moolenaar     atf_error_t err;
94c243e490SMarcel Moolenaar 
95c243e490SMarcel Moolenaar     PRE(!error_on_flight);
96c243e490SMarcel Moolenaar     PRE(data != NULL || datalen == 0);
97c243e490SMarcel Moolenaar     PRE(datalen != 0 || data == NULL);
98c243e490SMarcel Moolenaar 
99c243e490SMarcel Moolenaar     err = malloc(sizeof(*err));
100c243e490SMarcel Moolenaar     if (err == NULL)
101c243e490SMarcel Moolenaar         err = atf_no_memory_error();
102c243e490SMarcel Moolenaar     else {
103c243e490SMarcel Moolenaar         if (!error_init(err, type, data, datalen, format)) {
104c243e490SMarcel Moolenaar             free(err);
105c243e490SMarcel Moolenaar             err = atf_no_memory_error();
106c243e490SMarcel Moolenaar         } else {
107c243e490SMarcel Moolenaar             err->m_free = true;
108c243e490SMarcel Moolenaar             error_on_flight = true;
109c243e490SMarcel Moolenaar         }
110c243e490SMarcel Moolenaar     }
111c243e490SMarcel Moolenaar 
112c243e490SMarcel Moolenaar     INV(err != NULL);
113c243e490SMarcel Moolenaar     POST(error_on_flight);
114c243e490SMarcel Moolenaar     return err;
115c243e490SMarcel Moolenaar }
116c243e490SMarcel Moolenaar 
117c243e490SMarcel Moolenaar void
atf_error_free(atf_error_t err)118c243e490SMarcel Moolenaar atf_error_free(atf_error_t err)
119c243e490SMarcel Moolenaar {
120c243e490SMarcel Moolenaar     bool freeit;
121c243e490SMarcel Moolenaar 
122c243e490SMarcel Moolenaar     PRE(error_on_flight);
123c243e490SMarcel Moolenaar     PRE(err != NULL);
124c243e490SMarcel Moolenaar 
125c243e490SMarcel Moolenaar     freeit = err->m_free;
126c243e490SMarcel Moolenaar 
127c243e490SMarcel Moolenaar     if (err->m_data != NULL)
128c243e490SMarcel Moolenaar         free(err->m_data);
129c243e490SMarcel Moolenaar 
130c243e490SMarcel Moolenaar     if (freeit)
131c243e490SMarcel Moolenaar         free(err);
132c243e490SMarcel Moolenaar 
133c243e490SMarcel Moolenaar     error_on_flight = false;
134c243e490SMarcel Moolenaar }
135c243e490SMarcel Moolenaar 
136c243e490SMarcel Moolenaar atf_error_t
atf_no_error(void)137c243e490SMarcel Moolenaar atf_no_error(void)
138c243e490SMarcel Moolenaar {
139c243e490SMarcel Moolenaar     return NULL;
140c243e490SMarcel Moolenaar }
141c243e490SMarcel Moolenaar 
142c243e490SMarcel Moolenaar bool
atf_is_error(const atf_error_t err)143c243e490SMarcel Moolenaar atf_is_error(const atf_error_t err)
144c243e490SMarcel Moolenaar {
145c243e490SMarcel Moolenaar     return err != NULL;
146c243e490SMarcel Moolenaar }
147c243e490SMarcel Moolenaar 
148c243e490SMarcel Moolenaar bool
atf_error_is(const atf_error_t err,const char * type)149c243e490SMarcel Moolenaar atf_error_is(const atf_error_t err, const char *type)
150c243e490SMarcel Moolenaar {
151c243e490SMarcel Moolenaar     PRE(err != NULL);
152c243e490SMarcel Moolenaar 
153c243e490SMarcel Moolenaar     return strcmp(err->m_type, type) == 0;
154c243e490SMarcel Moolenaar }
155c243e490SMarcel Moolenaar 
156c243e490SMarcel Moolenaar const void *
atf_error_data(const atf_error_t err)157c243e490SMarcel Moolenaar atf_error_data(const atf_error_t err)
158c243e490SMarcel Moolenaar {
159c243e490SMarcel Moolenaar     PRE(err != NULL);
160c243e490SMarcel Moolenaar 
161c243e490SMarcel Moolenaar     return err->m_data;
162c243e490SMarcel Moolenaar }
163c243e490SMarcel Moolenaar 
164c243e490SMarcel Moolenaar void
atf_error_format(const atf_error_t err,char * buf,size_t buflen)165c243e490SMarcel Moolenaar atf_error_format(const atf_error_t err, char *buf, size_t buflen)
166c243e490SMarcel Moolenaar {
167c243e490SMarcel Moolenaar     PRE(err != NULL);
168c243e490SMarcel Moolenaar     err->m_format(err, buf, buflen);
169c243e490SMarcel Moolenaar }
170c243e490SMarcel Moolenaar 
171c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
172c243e490SMarcel Moolenaar  * Common error types.
173c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
174c243e490SMarcel Moolenaar 
175c243e490SMarcel Moolenaar /*
176c243e490SMarcel Moolenaar  * The "libc" error.
177c243e490SMarcel Moolenaar  */
178c243e490SMarcel Moolenaar 
179c243e490SMarcel Moolenaar struct atf_libc_error_data {
180c243e490SMarcel Moolenaar     int m_errno;
181c243e490SMarcel Moolenaar     char m_what[4096];
182c243e490SMarcel Moolenaar };
183c243e490SMarcel Moolenaar typedef struct atf_libc_error_data atf_libc_error_data_t;
184c243e490SMarcel Moolenaar 
185c243e490SMarcel Moolenaar static
186c243e490SMarcel Moolenaar void
libc_format(const atf_error_t err,char * buf,size_t buflen)187c243e490SMarcel Moolenaar libc_format(const atf_error_t err, char *buf, size_t buflen)
188c243e490SMarcel Moolenaar {
189c243e490SMarcel Moolenaar     const atf_libc_error_data_t *data;
190c243e490SMarcel Moolenaar 
191c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "libc"));
192c243e490SMarcel Moolenaar 
193c243e490SMarcel Moolenaar     data = atf_error_data(err);
194c243e490SMarcel Moolenaar     snprintf(buf, buflen, "%s: %s", data->m_what, strerror(data->m_errno));
195c243e490SMarcel Moolenaar }
196c243e490SMarcel Moolenaar 
197c243e490SMarcel Moolenaar atf_error_t
atf_libc_error(int syserrno,const char * fmt,...)198c243e490SMarcel Moolenaar atf_libc_error(int syserrno, const char *fmt, ...)
199c243e490SMarcel Moolenaar {
200c243e490SMarcel Moolenaar     atf_error_t err;
201c243e490SMarcel Moolenaar     atf_libc_error_data_t data;
202c243e490SMarcel Moolenaar     va_list ap;
203c243e490SMarcel Moolenaar 
204c243e490SMarcel Moolenaar     data.m_errno = syserrno;
205c243e490SMarcel Moolenaar     va_start(ap, fmt);
206c243e490SMarcel Moolenaar     vsnprintf(data.m_what, sizeof(data.m_what), fmt, ap);
207c243e490SMarcel Moolenaar     va_end(ap);
208c243e490SMarcel Moolenaar 
209c243e490SMarcel Moolenaar     err = atf_error_new("libc", &data, sizeof(data), libc_format);
210c243e490SMarcel Moolenaar 
211c243e490SMarcel Moolenaar     return err;
212c243e490SMarcel Moolenaar }
213c243e490SMarcel Moolenaar 
214c243e490SMarcel Moolenaar int
atf_libc_error_code(const atf_error_t err)215c243e490SMarcel Moolenaar atf_libc_error_code(const atf_error_t err)
216c243e490SMarcel Moolenaar {
217c243e490SMarcel Moolenaar     const struct atf_libc_error_data *data;
218c243e490SMarcel Moolenaar 
219c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "libc"));
220c243e490SMarcel Moolenaar 
221c243e490SMarcel Moolenaar     data = atf_error_data(err);
222c243e490SMarcel Moolenaar 
223c243e490SMarcel Moolenaar     return data->m_errno;
224c243e490SMarcel Moolenaar }
225c243e490SMarcel Moolenaar 
226c243e490SMarcel Moolenaar const char *
atf_libc_error_msg(const atf_error_t err)227c243e490SMarcel Moolenaar atf_libc_error_msg(const atf_error_t err)
228c243e490SMarcel Moolenaar {
229c243e490SMarcel Moolenaar     const struct atf_libc_error_data *data;
230c243e490SMarcel Moolenaar 
231c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "libc"));
232c243e490SMarcel Moolenaar 
233c243e490SMarcel Moolenaar     data = atf_error_data(err);
234c243e490SMarcel Moolenaar 
235c243e490SMarcel Moolenaar     return data->m_what;
236c243e490SMarcel Moolenaar }
237c243e490SMarcel Moolenaar 
238c243e490SMarcel Moolenaar /*
239c243e490SMarcel Moolenaar  * The "no_memory" error.
240c243e490SMarcel Moolenaar  */
241c243e490SMarcel Moolenaar 
242c243e490SMarcel Moolenaar static struct atf_error no_memory_error;
243c243e490SMarcel Moolenaar 
244c243e490SMarcel Moolenaar static
245c243e490SMarcel Moolenaar void
no_memory_format(const atf_error_t err,char * buf,size_t buflen)246c243e490SMarcel Moolenaar no_memory_format(const atf_error_t err, char *buf, size_t buflen)
247c243e490SMarcel Moolenaar {
248c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "no_memory"));
249c243e490SMarcel Moolenaar 
250c243e490SMarcel Moolenaar     snprintf(buf, buflen, "Not enough memory");
251c243e490SMarcel Moolenaar }
252c243e490SMarcel Moolenaar 
253c243e490SMarcel Moolenaar atf_error_t
atf_no_memory_error(void)254c243e490SMarcel Moolenaar atf_no_memory_error(void)
255c243e490SMarcel Moolenaar {
256c243e490SMarcel Moolenaar     PRE(!error_on_flight);
257c243e490SMarcel Moolenaar 
258c243e490SMarcel Moolenaar     error_init(&no_memory_error, "no_memory", NULL, 0,
259c243e490SMarcel Moolenaar                no_memory_format);
260c243e490SMarcel Moolenaar 
261c243e490SMarcel Moolenaar     error_on_flight = true;
262c243e490SMarcel Moolenaar     return &no_memory_error;
263c243e490SMarcel Moolenaar }
264