1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
20178825Sdfr *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr
36178825Sdfr/**
37178825Sdfr * @page page_error Hx509 error reporting functions
38178825Sdfr *
39178825Sdfr * See the library functions here: @ref hx509_error
40178825Sdfr */
41178825Sdfr
42178825Sdfrstruct hx509_error_data {
43178825Sdfr    hx509_error next;
44178825Sdfr    int code;
45178825Sdfr    char *msg;
46178825Sdfr};
47178825Sdfr
48178825Sdfrstatic void
49178825Sdfrfree_error_string(hx509_error msg)
50178825Sdfr{
51178825Sdfr    while(msg) {
52178825Sdfr	hx509_error m2 = msg->next;
53178825Sdfr	free(msg->msg);
54178825Sdfr	free(msg);
55178825Sdfr	msg = m2;
56178825Sdfr    }
57178825Sdfr}
58178825Sdfr
59178825Sdfr/**
60178825Sdfr * Resets the error strings the hx509 context.
61178825Sdfr *
62178825Sdfr * @param context A hx509 context.
63178825Sdfr *
64178825Sdfr * @ingroup hx509_error
65178825Sdfr */
66178825Sdfr
67178825Sdfrvoid
68178825Sdfrhx509_clear_error_string(hx509_context context)
69178825Sdfr{
70233294Sstas    if (context) {
71233294Sstas	free_error_string(context->error);
72233294Sstas	context->error = NULL;
73233294Sstas    }
74178825Sdfr}
75178825Sdfr
76178825Sdfr/**
77178825Sdfr * Add an error message to the hx509 context.
78178825Sdfr *
79178825Sdfr * @param context A hx509 context.
80178825Sdfr * @param flags
81178825Sdfr * - HX509_ERROR_APPEND appends the error string to the old messages
82178825Sdfr     (code is updated).
83178825Sdfr * @param code error code related to error message
84178825Sdfr * @param fmt error message format
85178825Sdfr * @param ap arguments to error message format
86178825Sdfr *
87178825Sdfr * @ingroup hx509_error
88178825Sdfr */
89178825Sdfr
90178825Sdfrvoid
91233294Sstashx509_set_error_stringv(hx509_context context, int flags, int code,
92178825Sdfr			const char *fmt, va_list ap)
93178825Sdfr{
94178825Sdfr    hx509_error msg;
95178825Sdfr
96233294Sstas    if (context == NULL)
97233294Sstas	return;
98233294Sstas
99178825Sdfr    msg = calloc(1, sizeof(*msg));
100178825Sdfr    if (msg == NULL) {
101178825Sdfr	hx509_clear_error_string(context);
102178825Sdfr	return;
103178825Sdfr    }
104178825Sdfr
105178825Sdfr    if (vasprintf(&msg->msg, fmt, ap) == -1) {
106178825Sdfr	hx509_clear_error_string(context);
107178825Sdfr	free(msg);
108178825Sdfr	return;
109178825Sdfr    }
110178825Sdfr    msg->code = code;
111178825Sdfr
112178825Sdfr    if (flags & HX509_ERROR_APPEND) {
113178825Sdfr	msg->next = context->error;
114178825Sdfr	context->error = msg;
115178825Sdfr    } else  {
116178825Sdfr	free_error_string(context->error);
117178825Sdfr	context->error = msg;
118178825Sdfr    }
119178825Sdfr}
120178825Sdfr
121178825Sdfr/**
122233294Sstas * See hx509_set_error_stringv().
123178825Sdfr *
124178825Sdfr * @param context A hx509 context.
125178825Sdfr * @param flags
126178825Sdfr * - HX509_ERROR_APPEND appends the error string to the old messages
127178825Sdfr     (code is updated).
128178825Sdfr * @param code error code related to error message
129178825Sdfr * @param fmt error message format
130178825Sdfr * @param ... arguments to error message format
131178825Sdfr *
132178825Sdfr * @ingroup hx509_error
133178825Sdfr */
134178825Sdfr
135178825Sdfrvoid
136178825Sdfrhx509_set_error_string(hx509_context context, int flags, int code,
137178825Sdfr		       const char *fmt, ...)
138178825Sdfr{
139178825Sdfr    va_list ap;
140178825Sdfr
141178825Sdfr    va_start(ap, fmt);
142178825Sdfr    hx509_set_error_stringv(context, flags, code, fmt, ap);
143178825Sdfr    va_end(ap);
144178825Sdfr}
145178825Sdfr
146178825Sdfr/**
147178825Sdfr * Get an error string from context associated with error_code.
148178825Sdfr *
149178825Sdfr * @param context A hx509 context.
150178825Sdfr * @param error_code Get error message for this error code.
151178825Sdfr *
152178825Sdfr * @return error string, free with hx509_free_error_string().
153178825Sdfr *
154178825Sdfr * @ingroup hx509_error
155178825Sdfr */
156178825Sdfr
157178825Sdfrchar *
158178825Sdfrhx509_get_error_string(hx509_context context, int error_code)
159178825Sdfr{
160178825Sdfr    struct rk_strpool *p = NULL;
161178825Sdfr    hx509_error msg = context->error;
162178825Sdfr
163178825Sdfr    if (msg == NULL || msg->code != error_code) {
164178825Sdfr	const char *cstr;
165178825Sdfr	char *str;
166178825Sdfr
167178825Sdfr	cstr = com_right(context->et_list, error_code);
168178825Sdfr	if (cstr)
169178825Sdfr	    return strdup(cstr);
170178825Sdfr	cstr = strerror(error_code);
171178825Sdfr	if (cstr)
172178825Sdfr	    return strdup(cstr);
173178825Sdfr	if (asprintf(&str, "<unknown error: %d>", error_code) == -1)
174178825Sdfr	    return NULL;
175178825Sdfr	return str;
176178825Sdfr    }
177178825Sdfr
178178825Sdfr    for (msg = context->error; msg; msg = msg->next)
179233294Sstas	p = rk_strpoolprintf(p, "%s%s", msg->msg,
180178825Sdfr			     msg->next != NULL ? "; " : "");
181178825Sdfr
182178825Sdfr    return rk_strpoolcollect(p);
183178825Sdfr}
184178825Sdfr
185178825Sdfr/**
186178825Sdfr * Free error string returned by hx509_get_error_string().
187178825Sdfr *
188178825Sdfr * @param str error string to free.
189178825Sdfr *
190178825Sdfr * @ingroup hx509_error
191178825Sdfr */
192178825Sdfr
193178825Sdfrvoid
194178825Sdfrhx509_free_error_string(char *str)
195178825Sdfr{
196178825Sdfr    free(str);
197178825Sdfr}
198178825Sdfr
199178825Sdfr/**
200178825Sdfr * Print error message and fatally exit from error code
201178825Sdfr *
202178825Sdfr * @param context A hx509 context.
203178825Sdfr * @param exit_code exit() code from process.
204178825Sdfr * @param error_code Error code for the reason to exit.
205178825Sdfr * @param fmt format string with the exit message.
206178825Sdfr * @param ... argument to format string.
207178825Sdfr *
208178825Sdfr * @ingroup hx509_error
209178825Sdfr */
210178825Sdfr
211178825Sdfrvoid
212233294Sstashx509_err(hx509_context context, int exit_code,
213178825Sdfr	  int error_code, const char *fmt, ...)
214178825Sdfr{
215178825Sdfr    va_list ap;
216178825Sdfr    const char *msg;
217178825Sdfr    char *str;
218178825Sdfr
219178825Sdfr    va_start(ap, fmt);
220178825Sdfr    vasprintf(&str, fmt, ap);
221178825Sdfr    va_end(ap);
222178825Sdfr    msg = hx509_get_error_string(context, error_code);
223178825Sdfr    if (msg == NULL)
224178825Sdfr	msg = "no error";
225178825Sdfr
226178825Sdfr    errx(exit_code, "%s: %s", str, msg);
227178825Sdfr}
228