blob: a00e8dbd21a46b6dfc8dd916b974ca44aa677950 [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
Dave Barachc3799992016-08-15 11:12:27 -040041#include <vppinfra/clib.h> /* for HAVE_ERRNO */
Ed Warnickecb9cada2015-12-08 15:45:58 -070042
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
Dave Barachc3799992016-08-15 11:12:27 -040055#include <vppinfra/standalone_stdio.h> /* for printf */
Ed Warnickecb9cada2015-12-08 15:45:58 -070056#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>
Dave Barachc3799992016-08-15 11:12:27 -040064#include <vppinfra/os.h> /* for os_panic/os_exit/os_puts */
Ed Warnickecb9cada2015-12-08 15:45:58 -070065
Dave Barachc3799992016-08-15 11:12:27 -040066typedef struct
67{
68 clib_error_handler_func_t *func;
69 void *arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -070070} clib_error_handler_t;
71
Dave Barachc3799992016-08-15 11:12:27 -040072static clib_error_handler_t *handlers = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070073
Damjan Mariondae1c7e2020-10-17 13:32:25 +020074__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -040075clib_error_register_handler (clib_error_handler_func_t func, void *arg)
Ed Warnickecb9cada2015-12-08 15:45:58 -070076{
Dave Barachc3799992016-08-15 11:12:27 -040077 clib_error_handler_t h = {.func = func,.arg = arg, };
Ed Warnickecb9cada2015-12-08 15:45:58 -070078 vec_add1 (handlers, h);
79}
80
Dave Barachc3799992016-08-15 11:12:27 -040081static void
82debugger (void)
Ed Warnickecb9cada2015-12-08 15:45:58 -070083{
84 os_panic ();
85}
86
Dave Barachc3799992016-08-15 11:12:27 -040087static void
88error_exit (int code)
Ed Warnickecb9cada2015-12-08 15:45:58 -070089{
90 os_exit (code);
91}
92
Dave Barachc3799992016-08-15 11:12:27 -040093static u8 *
94dispatch_message (u8 * msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -070095{
96 word i;
97
Dave Barachc3799992016-08-15 11:12:27 -040098 if (!msg)
Ed Warnickecb9cada2015-12-08 15:45:58 -070099 return msg;
100
101 for (i = 0; i < vec_len (handlers); i++)
102 handlers[i].func (handlers[i].arg, msg, vec_len (msg));
103
104 /* If no message handler is specified provide a default one. */
105 if (vec_len (handlers) == 0)
106 os_puts (msg, vec_len (msg), /* is_error */ 1);
107
108 return msg;
109}
110
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200111__clib_export void
Dave Barachc3799992016-08-15 11:12:27 -0400112_clib_error (int how_to_die,
113 char *function_name, uword line_number, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114{
Dave Barachc3799992016-08-15 11:12:27 -0400115 u8 *msg = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 va_list va;
117
118 if (function_name)
119 {
120 msg = format (msg, "%s:", function_name);
121 if (line_number > 0)
122 msg = format (msg, "%wd:", line_number);
123 msg = format (msg, " ");
124 }
125
126 va_start (va, fmt);
127 msg = va_format (msg, fmt, &va);
128 va_end (va);
129
130#ifdef HAVE_ERRNO
131 if (how_to_die & CLIB_ERROR_ERRNO_VALID)
132 msg = format (msg, ": %s (errno %d)", strerror (errno), errno);
133#endif
134
135 if (vec_end (msg)[-1] != '\n')
136 vec_add1 (msg, '\n');
137
138 msg = dispatch_message (msg);
139
140 vec_free (msg);
141
142 if (how_to_die & CLIB_ERROR_ABORT)
143 debugger ();
144 if (how_to_die & CLIB_ERROR_FATAL)
145 error_exit (1);
146}
147
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200148__clib_export clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -0400149_clib_error_return (clib_error_t * errors,
150 any code, uword flags, char *where, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151{
Dave Barachc3799992016-08-15 11:12:27 -0400152 clib_error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 va_list va;
154
155#ifdef HAVE_ERRNO
156 /* Save errno since it may be re-set before we'll need it. */
157 word errno_save = errno;
158#endif
159
160 va_start (va, fmt);
161 vec_add2 (errors, e, 1);
162 if (fmt)
163 e->what = va_format (0, fmt, &va);
164
165#ifdef HAVE_ERRNO
166 if (flags & CLIB_ERROR_ERRNO_VALID)
167 {
168 if (e->what)
169 e->what = format (e->what, ": ");
170 e->what = format (e->what, "%s", strerror (errno_save));
171 }
172#endif
Dave Barachc3799992016-08-15 11:12:27 -0400173
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174 e->where = (u8 *) where;
175 e->code = code;
176 e->flags = flags;
177 va_end (va);
178 return errors;
179}
180
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200181__clib_export void *
Dave Barachc3799992016-08-15 11:12:27 -0400182clib_error_free_vector (clib_error_t * errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700183{
Dave Barachc3799992016-08-15 11:12:27 -0400184 clib_error_t *e;
185 vec_foreach (e, errors) vec_free (e->what);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186 vec_free (errors);
187 return 0;
188}
189
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200190__clib_export u8 *
Dave Barachc3799992016-08-15 11:12:27 -0400191format_clib_error (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192{
Dave Barachc3799992016-08-15 11:12:27 -0400193 clib_error_t *errors = va_arg (*va, clib_error_t *);
194 clib_error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
196 vec_foreach (e, errors)
Dave Barachc3799992016-08-15 11:12:27 -0400197 {
198 if (!e->what)
199 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700200
Dave Barachc3799992016-08-15 11:12:27 -0400201 if (e->where)
202 {
203 u8 *where = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204
Dave Barachc3799992016-08-15 11:12:27 -0400205 if (e > errors)
206 where = format (where, "from ");
207 where = format (where, "%s", e->where);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208
Dave Barachc3799992016-08-15 11:12:27 -0400209 s = format (s, "%v: ", where);
210 vec_free (where);
211 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212
Dave Barachc3799992016-08-15 11:12:27 -0400213 s = format (s, "%v\n", e->what);
214 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215
216 return s;
217}
218
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200219__clib_export clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -0400220_clib_error_report (clib_error_t * errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221{
222 if (errors)
223 {
Dave Barachc3799992016-08-15 11:12:27 -0400224 u8 *msg = format (0, "%U", format_clib_error, errors);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225
226 msg = dispatch_message (msg);
227 vec_free (msg);
228
229 if (errors->flags & CLIB_ERROR_ABORT)
230 debugger ();
231 if (errors->flags & CLIB_ERROR_FATAL)
232 error_exit (1);
233
234 clib_error_free (errors);
235 }
236 return 0;
237}
238
239#ifdef TEST
240
Dave Barachc3799992016-08-15 11:12:27 -0400241static error_t *
242foo1 (int x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243{
244 return error_return (0, "x is odd %d", x);
245}
246
Dave Barachc3799992016-08-15 11:12:27 -0400247static error_t *
248foo2 (int x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249{
250 return error_return (0, "x is even %d", x);
251}
252
Dave Barachc3799992016-08-15 11:12:27 -0400253static error_t *
254foo (int x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255{
Dave Barachc3799992016-08-15 11:12:27 -0400256 error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257 if (x & 1)
258 e = foo1 (x);
259 else
260 e = foo2 (x);
261 if (e)
262 return error_return (e, 0);
263}
264
Dave Barachc3799992016-08-15 11:12:27 -0400265static void
266error_handler (void *arg, char *msg, int msg_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267{
268 write (2, msg, msg_len);
269}
270
Dave Barachc3799992016-08-15 11:12:27 -0400271int
272main (int argc, char *argv[])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273{
Dave Barachc3799992016-08-15 11:12:27 -0400274 error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275
276 register_error_handler (error_handler, 0);
277
278 e = foo (getpid ());
279 if (e)
280 error_report (e);
281 return 0;
282}
283
284#endif
Dave Barachc3799992016-08-15 11:12:27 -0400285
286/*
287 * fd.io coding-style-patch-verification: ON
288 *
289 * Local Variables:
290 * eval: (c-set-style "gnu")
291 * End:
292 */