Reorganize source tree to use single autotools instance
[vpp.git] / src / vppinfra / error.c
1 /*
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
66 typedef struct
67 {
68   clib_error_handler_func_t *func;
69   void *arg;
70 } clib_error_handler_t;
71
72 static clib_error_handler_t *handlers = 0;
73
74 void
75 clib_error_register_handler (clib_error_handler_func_t func, void *arg)
76 {
77   clib_error_handler_t h = {.func = func,.arg = arg, };
78   vec_add1 (handlers, h);
79 }
80
81 static void
82 debugger (void)
83 {
84   os_panic ();
85 }
86
87 static void
88 error_exit (int code)
89 {
90   os_exit (code);
91 }
92
93 static u8 *
94 dispatch_message (u8 * msg)
95 {
96   word i;
97
98   if (!msg)
99     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
111 void
112 _clib_error (int how_to_die,
113              char *function_name, uword line_number, char *fmt, ...)
114 {
115   u8 *msg = 0;
116   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
148 clib_error_t *
149 _clib_error_return (clib_error_t * errors,
150                     any code, uword flags, char *where, char *fmt, ...)
151 {
152   clib_error_t *e;
153   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
173
174   e->where = (u8 *) where;
175   e->code = code;
176   e->flags = flags;
177   va_end (va);
178   return errors;
179 }
180
181 void *
182 clib_error_free_vector (clib_error_t * errors)
183 {
184   clib_error_t *e;
185   vec_foreach (e, errors) vec_free (e->what);
186   vec_free (errors);
187   return 0;
188 }
189
190 u8 *
191 format_clib_error (u8 * s, va_list * va)
192 {
193   clib_error_t *errors = va_arg (*va, clib_error_t *);
194   clib_error_t *e;
195
196   vec_foreach (e, errors)
197   {
198     if (!e->what)
199       continue;
200
201     if (e->where)
202       {
203         u8 *where = 0;
204
205         if (e > errors)
206           where = format (where, "from ");
207         where = format (where, "%s", e->where);
208
209         s = format (s, "%v: ", where);
210         vec_free (where);
211       }
212
213     s = format (s, "%v\n", e->what);
214   }
215
216   return s;
217 }
218
219 clib_error_t *
220 _clib_error_report (clib_error_t * errors)
221 {
222   if (errors)
223     {
224       u8 *msg = format (0, "%U", format_clib_error, errors);
225
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
241 static error_t *
242 foo1 (int x)
243 {
244   return error_return (0, "x is odd %d", x);
245 }
246
247 static error_t *
248 foo2 (int x)
249 {
250   return error_return (0, "x is even %d", x);
251 }
252
253 static error_t *
254 foo (int x)
255 {
256   error_t *e;
257   if (x & 1)
258     e = foo1 (x);
259   else
260     e = foo2 (x);
261   if (e)
262     return error_return (e, 0);
263 }
264
265 static void
266 error_handler (void *arg, char *msg, int msg_len)
267 {
268   write (2, msg, msg_len);
269 }
270
271 int
272 main (int argc, char *argv[])
273 {
274   error_t *e;
275
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
285
286 /*
287  * fd.io coding-style-patch-verification: ON
288  *
289  * Local Variables:
290  * eval: (c-set-style "gnu")
291  * End:
292  */