1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2007 The NetBSD Foundation, Inc.
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
10// 1. Redistributions of source code must retain the above copyright
11//    notice, this list of conditions and the following disclaimer.
12// 2. Redistributions in binary form must reproduce the above copyright
13//    notice, this list of conditions and the following disclaimer in the
14//    documentation and/or other materials provided with the distribution.
15//
16// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29
30#if defined(HAVE_CONFIG_H)
31#include "bconfig.h"
32#endif
33
34#include <cstdarg>
35#include <cstdio>
36#include <cstring>
37#include <new>
38
39extern "C" {
40#include "../../atf-c/error.h"
41};
42
43#include "exceptions.hpp"
44#include "sanity.hpp"
45
46// ------------------------------------------------------------------------
47// The "system_error" type.
48// ------------------------------------------------------------------------
49
50atf::system_error::system_error(const std::string& who,
51                                const std::string& message,
52                                int sys_err) :
53    std::runtime_error(who + ": " + message),
54    m_sys_err(sys_err)
55{
56}
57
58atf::system_error::~system_error(void)
59    throw()
60{
61}
62
63int
64atf::system_error::code(void)
65    const
66    throw()
67{
68    return m_sys_err;
69}
70
71const char*
72atf::system_error::what(void)
73    const
74    throw()
75{
76    try {
77        if (m_message.length() == 0) {
78            m_message = std::string(std::runtime_error::what()) + ": ";
79            m_message += ::strerror(m_sys_err);
80        }
81
82        return m_message.c_str();
83    } catch (...) {
84        return "Unable to format system_error message";
85    }
86}
87
88// ------------------------------------------------------------------------
89// Free functions.
90// ------------------------------------------------------------------------
91
92static
93void
94throw_libc_error(atf_error_t err)
95{
96    PRE(atf_error_is(err, "libc"));
97
98    const int ecode = atf_libc_error_code(err);
99    const std::string msg = atf_libc_error_msg(err);
100    atf_error_free(err);
101    throw atf::system_error("XXX", msg, ecode);
102}
103
104static
105void
106throw_no_memory_error(atf_error_t err)
107{
108    PRE(atf_error_is(err, "no_memory"));
109
110    atf_error_free(err);
111    throw std::bad_alloc();
112}
113
114static
115void
116throw_unknown_error(atf_error_t err)
117{
118    PRE(atf_is_error(err));
119
120    static char buf[4096];
121    atf_error_format(err, buf, sizeof(buf));
122    atf_error_free(err);
123    throw std::runtime_error(buf);
124}
125
126void
127atf::throw_atf_error(atf_error_t err)
128{
129    static struct handler {
130        const char* m_name;
131        void (*m_func)(atf_error_t);
132    } handlers[] = {
133        { "libc", throw_libc_error },
134        { "no_memory", throw_no_memory_error },
135        { NULL, throw_unknown_error },
136    };
137
138    PRE(atf_is_error(err));
139
140    handler* h = handlers;
141    while (h->m_name != NULL) {
142        if (atf_error_is(err, h->m_name)) {
143            h->m_func(err);
144            UNREACHABLE;
145        } else
146            h++;
147    }
148    // XXX: I'm not sure that raising an "unknown" error is a wise thing
149    // to do here.  The C++ binding is supposed to have feature parity
150    // with the C one, so all possible errors raised by the C library
151    // should have their counterpart in the C++ library.  Still, removing
152    // this will require some code auditing that I can't afford at the
153    // moment.
154    INV(h->m_name == NULL && h->m_func != NULL);
155    h->m_func(err);
156    UNREACHABLE;
157}
158