]> git.proxmox.com Git - mirror_frr.git/blob - lib/ferr.h
lib: Allow adding arrays of ferr's
[mirror_frr.git] / lib / ferr.h
1 /*
2 * Copyright (c) 2015-16 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #ifndef _FRR_FERR_H
18 #define _FRR_FERR_H
19
20 /***********************************************************
21 * scroll down to the end of this file for a full example! *
22 ***********************************************************/
23
24 #include <stdint.h>
25 #include <limits.h>
26 #include <errno.h>
27
28 #include "vty.h"
29
30 /* return type when this error indication stuff is used.
31 *
32 * guaranteed to have boolean evaluation to "false" when OK, "true" when error
33 * (i.e. can be changed to pointer in the future if neccessary)
34 *
35 * For checking, always use "if (value)", nothing else.
36 * Do _NOT_ use any integer constant (!= 0), or sign check (< 0).
37 */
38 typedef int ferr_r;
39
40 /* rough category of error indication */
41 enum ferr_kind {
42 /* no error */
43 FERR_OK = 0,
44
45 /* something isn't the way it's supposed to be.
46 * (things that might otherwise be asserts, really)
47 */
48 FERR_CODE_BUG,
49
50 /* user-supplied parameters don't make sense or is inconsistent
51 * if you can express a rule for it (e.g. "holdtime > 2 * keepalive"),
52 * it's this category.
53 */
54 FERR_CONFIG_INVALID,
55
56 /* user-supplied parameters don't line up with reality
57 * (IP address or interface not available, etc.)
58 * NB: these are really TODOs where the code needs to be fixed to
59 * respond to future changes!
60 */
61 FERR_CONFIG_REALITY,
62
63 /* out of some system resource (probably memory)
64 * aka "you didn't spend enough money error" */
65 FERR_RESOURCE,
66
67 /* system error (permission denied, etc.) */
68 FERR_SYSTEM,
69
70 /* error return from some external library
71 * (FERR_SYSTEM and FERR_LIBRARY are not strongly distinct) */
72 FERR_LIBRARY,
73 };
74
75 struct ferr {
76 /* code location */
77 const char *file;
78 const char *func;
79 int line;
80
81 enum ferr_kind kind;
82
83 /* unique_id is calculated as a checksum of source filename and error
84 * message format (*before* calling vsnprintf). Line number and
85 * function name are not used; this keeps the number reasonably static
86 * across changes.
87 */
88 uint32_t unique_id;
89
90 char message[384];
91
92 /* valid if != 0. note "errno" might be preprocessor foobar. */
93 int errno_val;
94 /* valid if pathname[0] != '\0' */
95 char pathname[PATH_MAX];
96 };
97
98 /* Numeric ranges assigned to daemons for use as error codes. */
99 #define LIB_FERR_START 0x01000001
100 #define LIB_FERR_END 0x01FFFFFF
101 #define BGP_FERR_START 0x02000000
102 #define BGP_FERR_END 0x02FFFFFF
103 #define OSPF_FERR_START 0x03000001
104 #define OSPF_FERR_END 0x03FFFFFF
105 #define ZEBRA_FERR_START 0x04000001
106 #define ZEBRA_FERR_END 0x04FFFFFF
107 #define END_FERR 0xFFFFFFFF
108
109 struct ferr_ref {
110 /* Unique error code displayed to end user as a reference. -1 means
111 * this is an uncoded error that does not have reference material. */
112 uint32_t code;
113 /* Ultra brief title */
114 const char *title;
115 /* Brief description of error */
116 const char *description;
117 /* Remedial suggestion */
118 const char *suggestion;
119 };
120
121 void ferr_ref_add(struct ferr_ref *ref);
122 struct ferr_ref *ferr_ref_get(uint32_t code);
123 void ferr_ref_display(struct vty *, uint32_t code);
124 void ferr_ref_init(void);
125 void ferr_ref_fini(void);
126
127 /* get error details.
128 *
129 * NB: errval/ferr_r does NOT carry the full error information. It's only
130 * passed around for future API flexibility. ferr_get_last always returns
131 * the last error set in the current thread.
132 */
133 const struct ferr *ferr_get_last(ferr_r errval);
134
135 /* can optionally be called at strategic locations.
136 * always returns 0. */
137 ferr_r ferr_clear(void);
138
139 /* do NOT call these functions directly. only for macro use! */
140 ferr_r ferr_set_internal(const char *file, int line, const char *func,
141 enum ferr_kind kind, const char *text, ...);
142 ferr_r ferr_set_internal_ext(const char *file, int line, const char *func,
143 enum ferr_kind kind, const char *pathname,
144 int errno_val, const char *text, ...);
145
146 #define ferr_ok() 0
147
148 /* Report an error.
149 *
150 * If you need to do cleanup (free memory, etc.), save the return value in a
151 * variable of type ferr_r.
152 *
153 * Don't put a \n at the end of the error message.
154 */
155 #define ferr_code_bug(...) \
156 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CODE_BUG, \
157 __VA_ARGS__)
158 #define ferr_cfg_invalid(...) \
159 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_INVALID, \
160 __VA_ARGS__)
161 #define ferr_cfg_reality(...) \
162 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_REALITY, \
163 __VA_ARGS__)
164 #define ferr_cfg_resource(...) \
165 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_RESOURCE, \
166 __VA_ARGS__)
167 #define ferr_system(...) \
168 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_SYSTEM, \
169 __VA_ARGS__)
170 #define ferr_library(...) \
171 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_LIBRARY, \
172 __VA_ARGS__)
173
174 /* extended information variants */
175 #define ferr_system_errno(...) \
176 ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, NULL, \
177 errno, __VA_ARGS__)
178 #define ferr_system_path_errno(path, ...) \
179 ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, path, \
180 errno, __VA_ARGS__)
181
182 #include "vty.h"
183 /* print error message to vty; $ERR is replaced by the error's message */
184 void vty_print_error(struct vty *vty, ferr_r err, const char *msg, ...);
185
186 #define CMD_FERR_DO(func, action, ...) \
187 do { \
188 ferr_r cmd_retval = func; \
189 if (cmd_retval) { \
190 vty_print_error(vty, cmd_retval, __VA_ARGS__); \
191 action; \
192 } \
193 } while (0)
194
195 #define CMD_FERR_RETURN(func, ...) \
196 CMD_FERR_DO(func, return CMD_WARNING_CONFIG_FAILED, __VA_ARGS__)
197 #define CMD_FERR_GOTO(func, label, ...) \
198 CMD_FERR_DO(func, goto label, __VA_ARGS__)
199
200 /* example: uses bogus #define to keep indent.py happy */
201 #ifdef THIS_IS_AN_EXAMPLE
202 ferr_r foo_bar_set(struct object *obj, int bar)
203 {
204 if (bar < 1 || bar >= 100)
205 return ferr_config_invalid("bar setting (%d) must be 0<x<100",
206 bar);
207 obj->bar = bar;
208 if (ioctl(obj->fd, bar))
209 return ferr_system_errno("couldn't set bar to %d", bar);
210
211 return ferr_ok();
212 }
213
214 DEFUN("bla")
215 {
216 CMD_FERR_RETURN(foo_bar_set(obj, atoi(argv[1])),
217 "command failed: $ERR\n");
218 return CMD_SUCCESS;
219 }
220
221 #endif /* THIS_IS_AN_EXAMPLE */
222
223 #endif /* _FERR_H */