vppinfra: add const to char* params of several funcs
[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 __clib_export 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 __clib_export void
112 _clib_error (int how_to_die, const char *function_name, uword line_number,
113              const 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_export clib_error_t *
149 _clib_error_return (clib_error_t *errors, any code, uword flags,
150                     const char *where, const 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 __clib_export 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 __clib_export 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", e->what);
214     if ((vec_end (errors) - 1) != e)
215       s = format (s, "\n");
216   }
217
218   return s;
219 }
220
221 __clib_export clib_error_t *
222 _clib_error_report (clib_error_t * errors)
223 {
224   if (errors)
225     {
226       u8 *msg = format (0, "%U", format_clib_error, errors);
227
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
243 static error_t *
244 foo1 (int x)
245 {
246   return error_return (0, "x is odd %d", x);
247 }
248
249 static error_t *
250 foo2 (int x)
251 {
252   return error_return (0, "x is even %d", x);
253 }
254
255 static error_t *
256 foo (int x)
257 {
258   error_t *e;
259   if (x & 1)
260     e = foo1 (x);
261   else
262     e = foo2 (x);
263   if (e)
264     return error_return (e, 0);
265 }
266
267 static void
268 error_handler (void *arg, char *msg, int msg_len)
269 {
270   write (2, msg, msg_len);
271 }
272
273 int
274 main (int argc, char *argv[])
275 {
276   error_t *e;
277
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
287
288 /*
289  * fd.io coding-style-patch-verification: ON
290  *
291  * Local Variables:
292  * eval: (c-set-style "gnu")
293  * End:
294  */