blob: 374b8b5256a6cebb7e083f6d24e26a052afb5fdf [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
Sergey Nikiforove5465322023-01-14 00:12:05 +0500112_clib_error (int how_to_die, const char *function_name, uword line_number,
113 const 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 *
Sergey Nikiforove5465322023-01-14 00:12:05 +0500149_clib_error_return (clib_error_t *errors, any code, uword flags,
150 const char *where, const 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
Damjan Marion06d82262020-10-21 12:43:40 +0200213 s = format (s, "%v", e->what);
214 if ((vec_end (errors) - 1) != e)
215 s = format (s, "\n");
Dave Barachc3799992016-08-15 11:12:27 -0400216 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217
218 return s;
219}
220
Damjan Mariondae1c7e2020-10-17 13:32:25 +0200221__clib_export clib_error_t *
Dave Barachc3799992016-08-15 11:12:27 -0400222_clib_error_report (clib_error_t * errors)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223{
224 if (errors)
225 {
Dave Barachc3799992016-08-15 11:12:27 -0400226 u8 *msg = format (0, "%U", format_clib_error, errors);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227
228 msg = dispatch_message (msg);
229 vec_free (msg);
230
231 if (errors->flags & CLIB_ERROR_ABORT)
232 debugger ();
233 if (errors->flags & CLIB_ERROR_FATAL)
234 error_exit (1);
235
236 clib_error_free (errors);
237 }
238 return 0;
239}
240
241#ifdef TEST
242
Dave Barachc3799992016-08-15 11:12:27 -0400243static error_t *
244foo1 (int x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245{
246 return error_return (0, "x is odd %d", x);
247}
248
Dave Barachc3799992016-08-15 11:12:27 -0400249static error_t *
250foo2 (int x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251{
252 return error_return (0, "x is even %d", x);
253}
254
Dave Barachc3799992016-08-15 11:12:27 -0400255static error_t *
256foo (int x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257{
Dave Barachc3799992016-08-15 11:12:27 -0400258 error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700259 if (x & 1)
260 e = foo1 (x);
261 else
262 e = foo2 (x);
263 if (e)
264 return error_return (e, 0);
265}
266
Dave Barachc3799992016-08-15 11:12:27 -0400267static void
268error_handler (void *arg, char *msg, int msg_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269{
270 write (2, msg, msg_len);
271}
272
Dave Barachc3799992016-08-15 11:12:27 -0400273int
274main (int argc, char *argv[])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275{
Dave Barachc3799992016-08-15 11:12:27 -0400276 error_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277
278 register_error_handler (error_handler, 0);
279
280 e = foo (getpid ());
281 if (e)
282 error_report (e);
283 return 0;
284}
285
286#endif
Dave Barachc3799992016-08-15 11:12:27 -0400287
288/*
289 * fd.io coding-style-patch-verification: ON
290 *
291 * Local Variables:
292 * eval: (c-set-style "gnu")
293 * End:
294 */