]> git.proxmox.com Git - mirror_frr.git/blame - lib/ferr.h
*: apply proper format string attributes
[mirror_frr.git] / lib / ferr.h
CommitLineData
3155489a
DL
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
7b526b61
QY
28#include "vty.h"
29
5e244469
RW
30#ifdef __cplusplus
31extern "C" {
32#endif
33
3155489a
DL
34/* return type when this error indication stuff is used.
35 *
36 * guaranteed to have boolean evaluation to "false" when OK, "true" when error
214d8a60 37 * (i.e. can be changed to pointer in the future if necessary)
3155489a
DL
38 *
39 * For checking, always use "if (value)", nothing else.
40 * Do _NOT_ use any integer constant (!= 0), or sign check (< 0).
41 */
42typedef int ferr_r;
43
44/* rough category of error indication */
45enum ferr_kind {
46 /* no error */
47 FERR_OK = 0,
48
49 /* something isn't the way it's supposed to be.
50 * (things that might otherwise be asserts, really)
51 */
52 FERR_CODE_BUG,
53
54 /* user-supplied parameters don't make sense or is inconsistent
55 * if you can express a rule for it (e.g. "holdtime > 2 * keepalive"),
56 * it's this category.
57 */
58 FERR_CONFIG_INVALID,
59
60 /* user-supplied parameters don't line up with reality
61 * (IP address or interface not available, etc.)
62 * NB: these are really TODOs where the code needs to be fixed to
63 * respond to future changes!
64 */
65 FERR_CONFIG_REALITY,
66
67 /* out of some system resource (probably memory)
68 * aka "you didn't spend enough money error" */
69 FERR_RESOURCE,
70
71 /* system error (permission denied, etc.) */
72 FERR_SYSTEM,
73
74 /* error return from some external library
75 * (FERR_SYSTEM and FERR_LIBRARY are not strongly distinct) */
76 FERR_LIBRARY,
77};
78
79struct ferr {
80 /* code location */
81 const char *file;
82 const char *func;
83 int line;
84
85 enum ferr_kind kind;
86
87 /* unique_id is calculated as a checksum of source filename and error
88 * message format (*before* calling vsnprintf). Line number and
89 * function name are not used; this keeps the number reasonably static
90 * across changes.
91 */
92 uint32_t unique_id;
93
94 char message[384];
95
96 /* valid if != 0. note "errno" might be preprocessor foobar. */
97 int errno_val;
98 /* valid if pathname[0] != '\0' */
99 char pathname[PATH_MAX];
100};
101
7b526b61 102/* Numeric ranges assigned to daemons for use as error codes. */
0f41a262
DS
103#define BABEL_FERR_START 0x01000001
104#define BABEL_FRRR_END 0x01FFFFFF
105#define BGP_FERR_START 0x02000001
106#define BGP_FERR_END 0x02FFFFFF
107#define EIGRP_FERR_START 0x03000001
108#define EIGRP_FERR_END 0x03FFFFFF
109#define ISIS_FERR_START 0x04000001
110#define ISIS_FERR_END 0x04FFFFFF
111#define LDP_FERR_START 0x05000001
112#define LDP_FERR_END 0x05FFFFFF
113#define LIB_FERR_START 0x06000001
114#define LIB_FERR_END 0x06FFFFFF
115#define NHRP_FERR_START 0x07000001
116#define NHRP_FERR_END 0x07FFFFFF
117#define OSPF_FERR_START 0x08000001
118#define OSPF_FERR_END 0x08FFFFFF
119#define OSPFV3_FERR_START 0x09000001
120#define OSPFV3_FERR_END 0x09FFFFFF
121#define PBR_FERR_START 0x0A000001
122#define PBR_FERR_END 0x0AFFFFFF
123#define PIM_FERR_START 0x0B000001
124#define PIM_FERR_STOP 0x0BFFFFFF
125#define RIP_FERR_START 0x0C000001
126#define RIP_FERR_STOP 0x0CFFFFFF
127#define RIPNG_FERR_START 0x0D000001
128#define RIPNG_FERR_STOP 0x0DFFFFFF
129#define SHARP_FERR_START 0x0E000001
130#define SHARP_FERR_END 0x0EFFFFFF
131#define VTYSH_FERR_START 0x0F000001
132#define VTYSH_FRR_END 0x0FFFFFFF
133#define WATCHFRR_FERR_START 0x10000001
134#define WATCHFRR_FERR_END 0x10FFFFFF
4d7b695d
SM
135#define PATH_FERR_START 0x11000001
136#define PATH_FERR_END 0x11FFFFFF
0f41a262
DS
137#define ZEBRA_FERR_START 0xF1000001
138#define ZEBRA_FERR_END 0xF1FFFFFF
139#define END_FERR 0xFFFFFFFF
7b526b61 140
85cd2f9f 141struct log_ref {
7b526b61
QY
142 /* Unique error code displayed to end user as a reference. -1 means
143 * this is an uncoded error that does not have reference material. */
144 uint32_t code;
145 /* Ultra brief title */
146 const char *title;
147 /* Brief description of error */
148 const char *description;
149 /* Remedial suggestion */
150 const char *suggestion;
151};
152
85cd2f9f
QY
153void log_ref_add(struct log_ref *ref);
154struct log_ref *log_ref_get(uint32_t code);
155void log_ref_display(struct vty *vty, uint32_t code, bool json);
b66d022e
DS
156
157/*
158 * This function should be called by the
159 * code in libfrr.c
160 */
85cd2f9f
QY
161void log_ref_init(void);
162void log_ref_fini(void);
1f9128d6 163void log_ref_vty_init(void);
7b526b61 164
3155489a
DL
165/* get error details.
166 *
167 * NB: errval/ferr_r does NOT carry the full error information. It's only
168 * passed around for future API flexibility. ferr_get_last always returns
169 * the last error set in the current thread.
170 */
171const struct ferr *ferr_get_last(ferr_r errval);
172
af4d3437
QY
173/*
174 * Can optionally be called at strategic locations.
175 * Always returns 0.
176 */
3155489a
DL
177ferr_r ferr_clear(void);
178
179/* do NOT call these functions directly. only for macro use! */
180ferr_r ferr_set_internal(const char *file, int line, const char *func,
0f9de11a
DL
181 enum ferr_kind kind, const char *text, ...)
182 PRINTFRR(5, 6);
3155489a 183ferr_r ferr_set_internal_ext(const char *file, int line, const char *func,
996c9314 184 enum ferr_kind kind, const char *pathname,
0f9de11a
DL
185 int errno_val, const char *text, ...)
186 PRINTFRR(7, 8);
3155489a 187
996c9314 188#define ferr_ok() 0
3155489a
DL
189
190/* Report an error.
191 *
192 * If you need to do cleanup (free memory, etc.), save the return value in a
193 * variable of type ferr_r.
194 *
195 * Don't put a \n at the end of the error message.
196 */
996c9314
LB
197#define ferr_code_bug(...) \
198 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CODE_BUG, \
199 __VA_ARGS__)
200#define ferr_cfg_invalid(...) \
201 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_INVALID, \
202 __VA_ARGS__)
203#define ferr_cfg_reality(...) \
204 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_REALITY, \
205 __VA_ARGS__)
206#define ferr_cfg_resource(...) \
207 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_RESOURCE, \
208 __VA_ARGS__)
209#define ferr_system(...) \
210 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_SYSTEM, \
211 __VA_ARGS__)
212#define ferr_library(...) \
213 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_LIBRARY, \
214 __VA_ARGS__)
3155489a
DL
215
216/* extended information variants */
996c9314
LB
217#define ferr_system_errno(...) \
218 ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, NULL, \
219 errno, __VA_ARGS__)
220#define ferr_system_path_errno(path, ...) \
221 ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, path, \
222 errno, __VA_ARGS__)
3155489a
DL
223
224#include "vty.h"
225/* print error message to vty; $ERR is replaced by the error's message */
0f9de11a
DL
226void vty_print_error(struct vty *vty, ferr_r err, const char *msg, ...)
227 PRINTFRR(3, 4);
3155489a 228
996c9314
LB
229#define CMD_FERR_DO(func, action, ...) \
230 do { \
231 ferr_r cmd_retval = func; \
232 if (cmd_retval) { \
233 vty_print_error(vty, cmd_retval, __VA_ARGS__); \
234 action; \
235 } \
3155489a
DL
236 } while (0)
237
996c9314 238#define CMD_FERR_RETURN(func, ...) \
7eb09438 239 CMD_FERR_DO(func, return CMD_WARNING_CONFIG_FAILED, __VA_ARGS__)
996c9314 240#define CMD_FERR_GOTO(func, label, ...) \
3155489a
DL
241 CMD_FERR_DO(func, goto label, __VA_ARGS__)
242
e894f9fd
LB
243/* example: uses bogus #define to keep indent.py happy */
244#ifdef THIS_IS_AN_EXAMPLE
3155489a
DL
245ferr_r foo_bar_set(struct object *obj, int bar)
246{
247 if (bar < 1 || bar >= 100)
e894f9fd
LB
248 return ferr_config_invalid("bar setting (%d) must be 0<x<100",
249 bar);
3155489a 250 obj->bar = bar;
e894f9fd 251 if (ioctl(obj->fd, bar))
3155489a
DL
252 return ferr_system_errno("couldn't set bar to %d", bar);
253
254 return ferr_ok();
255}
256
257DEFUN("bla")
258{
259 CMD_FERR_RETURN(foo_bar_set(obj, atoi(argv[1])),
996c9314 260 "command failed: $ERR\n");
3155489a
DL
261 return CMD_SUCCESS;
262}
263
e894f9fd 264#endif /* THIS_IS_AN_EXAMPLE */
3155489a 265
5e244469
RW
266#ifdef __cplusplus
267}
268#endif
269
3155489a 270#endif /* _FERR_H */