1//
2// Automated Testing Framework (atf)
3//
4// Copyright (c) 2007, 2008, 2009 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
38extern "C" {
39#include "../../atf-c/error.h"
40};
41
42#include "exceptions.hpp"
43#include "sanity.hpp"
44
45// ------------------------------------------------------------------------
46// The "system_error" type.
47// ------------------------------------------------------------------------
48
49atf::system_error::system_error(const std::string& who,
50                                const std::string& message,
51                                int sys_err) :
52    std::runtime_error(who + ": " + message),
53    m_sys_err(sys_err)
54{
55}
56
57atf::system_error::~system_error(void)
58    throw()
59{
60}
61
62int
63atf::system_error::code(void)
64    const
65    throw()
66{
67    return m_sys_err;
68}
69
70const char*
71atf::system_error::what(void)
72    const
73    throw()
74{
75    try {
76        if (m_message.length() == 0) {
77            m_message = std::string(std::runtime_error::what()) + ": ";
78            m_message += ::strerror(m_sys_err);
79        }
80
81        return m_message.c_str();
82    } catch (...) {
83        return "Unable to format system_error message";
84    }
85}
86
87// ------------------------------------------------------------------------
88// Free functions.
89// ------------------------------------------------------------------------
90
91static
92void
93throw_libc_error(atf_error_t err)
94{
95    PRE(atf_error_is(err, "libc"));
96
97    const int ecode = atf_libc_error_code(err);
98    const std::string msg = atf_libc_error_msg(err);
99    atf_error_free(err);
100    throw atf::system_error("XXX", msg, ecode);
101}
102
103static
104void
105throw_no_memory_error(atf_error_t err)
106{
107    PRE(atf_error_is(err, "no_memory"));
108
109    atf_error_free(err);
110    throw std::bad_alloc();
111}
112
113static
114void
115throw_unknown_error(atf_error_t err)
116{
117    PRE(atf_is_error(err));
118
119    static char buf[4096];
120    atf_error_format(err, buf, sizeof(buf));
121    atf_error_free(err);
122    throw std::runtime_error(buf);
123}
124
125void
126atf::throw_atf_error(atf_error_t err)
127{
128    static struct handler {
129        const char* m_name;
130        void (*m_func)(atf_error_t);
131    } handlers[] = {
132        { "libc", throw_libc_error },
133        { "no_memory", throw_no_memory_error },
134        { NULL, throw_unknown_error },
135    };
136
137    PRE(atf_is_error(err));
138
139    handler* h = handlers;
140    while (h->m_name != NULL) {
141        if (atf_error_is(err, h->m_name)) {
142            h->m_func(err);
143            UNREACHABLE;
144        } else
145            h++;
146    }
147    // XXX: I'm not sure that raising an "unknown" error is a wise thing
148    // to do here.  The C++ binding is supposed to have feature parity
149    // with the C one, so all possible errors raised by the C library
150    // should have their counterpart in the C++ library.  Still, removing
151    // this will require some code auditing that I can't afford at the
152    // moment.
153    INV(h->m_name == NULL && h->m_func != NULL);
154    h->m_func(err);
155    UNREACHABLE;
156}
157