blob: 1af9eb0f5157e387b6276a7dca59728e719656fe [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38/* Error reporting. */
39#include <stdarg.h>
40
41#include <vppinfra/clib.h> /* for HAVE_ERRNO */
42
43#ifdef CLIB_LINUX_KERNEL
44#include <linux/unistd.h> /* for write */
45#include <linux/kernel.h> /* for printk */
46#endif
47
48#ifdef CLIB_UNIX
49#include <unistd.h> /* for write */
50#include <stdio.h> /* for printf */
51#define HAVE_ERRNO
52#endif
53
54#ifdef CLIB_STANDALONE
55#include <vppinfra/standalone_stdio.h> /* for printf */
56#endif
57
58#include <vppinfra/string.h>
59#include <vppinfra/mem.h>
60#include <vppinfra/vec.h>
61#include <vppinfra/format.h>
62#include <vppinfra/error.h>
63#include <vppinfra/hash.h>
64#include <vppinfra/os.h> /* for os_panic/os_exit/os_puts */
65
66typedef struct {
67 clib_error_handler_func_t * func;
68 void * arg;
69} clib_error_handler_t;
70
71static clib_error_handler_t * handlers = 0;
72
73void clib_error_register_handler (clib_error_handler_func_t func, void * arg)
74{
75 clib_error_handler_t h = { .func = func, .arg = arg, };
76 vec_add1 (handlers, h);
77}
78
79static void debugger (void)
80{
81 os_panic ();
82}
83
84static void error_exit (int code)
85{
86 os_exit (code);
87}
88
89static u8 * dispatch_message (u8 * msg)
90{
91 word i;
92
93 if (! msg)
94 return msg;
95
96 for (i = 0; i < vec_len (handlers); i++)
97 handlers[i].func (handlers[i].arg, msg, vec_len (msg));
98
99 /* If no message handler is specified provide a default one. */
100 if (vec_len (handlers) == 0)
101 os_puts (msg, vec_len (msg), /* is_error */ 1);
102
103 return msg;
104}
105
106void _clib_error (int how_to_die,
107 char * function_name,
108 uword line_number,
109 char * fmt, ...)
110{
111 u8 * msg = 0;
112 va_list va;
113
114 if (function_name)
115 {
116 msg = format (msg, "%s:", function_name);
117 if (line_number > 0)
118 msg = format (msg, "%wd:", line_number);
119 msg = format (msg, " ");
120 }
121
122 va_start (va, fmt);
123 msg = va_format (msg, fmt, &va);
124 va_end (va);
125
126#ifdef HAVE_ERRNO
127 if (how_to_die & CLIB_ERROR_ERRNO_VALID)
128 msg = format (msg, ": %s (errno %d)", strerror (errno), errno);
129#endif
130
131 if (vec_end (msg)[-1] != '\n')
132 vec_add1 (msg, '\n');
133
134 msg = dispatch_message (msg);
135
136 vec_free (msg);
137
138 if (how_to_die & CLIB_ERROR_ABORT)
139 debugger ();
140 if (how_to_die & CLIB_ERROR_FATAL)
141 error_exit (1);
142}
143
144clib_error_t * _clib_error_return (clib_error_t * errors,
145 any code,
146 uword flags,
147 char * where,
148 char * fmt, ...)
149{
150 clib_error_t * e;
151 va_list va;
152
153#ifdef HAVE_ERRNO
154 /* Save errno since it may be re-set before we'll need it. */
155 word errno_save = errno;
156#endif
157
158 va_start (va, fmt);
159 vec_add2 (errors, e, 1);
160 if (fmt)
161 e->what = va_format (0, fmt, &va);
162
163#ifdef HAVE_ERRNO
164 if (flags & CLIB_ERROR_ERRNO_VALID)
165 {
166 if (e->what)
167 e->what = format (e->what, ": ");
168 e->what = format (e->what, "%s", strerror (errno_save));
169 }
170#endif
171
172 e->where = (u8 *) where;
173 e->code = code;
174 e->flags = flags;
175 va_end (va);
176 return errors;
177}
178
179void * clib_error_free_vector (clib_error_t * errors)
180{
181 clib_error_t * e;
182 vec_foreach (e, errors)
183 vec_free (e->what);
184 vec_free (errors);
185 return 0;
186}
187
188u8 * format_clib_error (u8 * s, va_list * va)
189{
190 clib_error_t * errors = va_arg (*va, clib_error_t *);
191 clib_error_t * e;
192
193 vec_foreach (e, errors)
194 {
195 if (! e->what)
196 continue;
197
198 if (e->where)
199 {
200 u8 * where = 0;
201
202 if (e > errors)
203 where = format (where, "from ");
204 where = format (where, "%s", e->where);
205
206 s = format (s, "%v: ", where);
207 vec_free (where);
208 }
209
210 s = format (s, "%v\n", e->what);
211 }
212
213 return s;
214}
215
216clib_error_t * _clib_error_report (clib_error_t * errors)
217{
218 if (errors)
219 {
220 u8 * msg = format (0, "%U", format_clib_error, errors);
221
222 msg = dispatch_message (msg);
223 vec_free (msg);
224
225 if (errors->flags & CLIB_ERROR_ABORT)
226 debugger ();
227 if (errors->flags & CLIB_ERROR_FATAL)
228 error_exit (1);
229
230 clib_error_free (errors);
231 }
232 return 0;
233}
234
235#ifdef TEST
236
237static error_t * foo1 (int x)
238{
239 return error_return (0, "x is odd %d", x);
240}
241
242static error_t * foo2 (int x)
243{
244 return error_return (0, "x is even %d", x);
245}
246
247static error_t * foo (int x)
248{
249 error_t * e;
250 if (x & 1)
251 e = foo1 (x);
252 else
253 e = foo2 (x);
254 if (e)
255 return error_return (e, 0);
256}
257
258static void error_handler (void * arg, char * msg, int msg_len)
259{
260 write (2, msg, msg_len);
261}
262
263int main (int argc, char * argv[])
264{
265 error_t * e;
266
267 register_error_handler (error_handler, 0);
268
269 e = foo (getpid ());
270 if (e)
271 error_report (e);
272 return 0;
273}
274
275#endif