]> git.proxmox.com Git - mirror_frr.git/blob - lib/ferr.h
lib: Convert internal sequence number to int64_t
[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 /* return type when this error indication stuff is used.
29 *
30 * guaranteed to have boolean evaluation to "false" when OK, "true" when error
31 * (i.e. can be changed to pointer in the future if neccessary)
32 *
33 * For checking, always use "if (value)", nothing else.
34 * Do _NOT_ use any integer constant (!= 0), or sign check (< 0).
35 */
36 typedef int ferr_r;
37
38 /* rough category of error indication */
39 enum ferr_kind {
40 /* no error */
41 FERR_OK = 0,
42
43 /* something isn't the way it's supposed to be.
44 * (things that might otherwise be asserts, really)
45 */
46 FERR_CODE_BUG,
47
48 /* user-supplied parameters don't make sense or is inconsistent
49 * if you can express a rule for it (e.g. "holdtime > 2 * keepalive"),
50 * it's this category.
51 */
52 FERR_CONFIG_INVALID,
53
54 /* user-supplied parameters don't line up with reality
55 * (IP address or interface not available, etc.)
56 * NB: these are really TODOs where the code needs to be fixed to
57 * respond to future changes!
58 */
59 FERR_CONFIG_REALITY,
60
61 /* out of some system resource (probably memory)
62 * aka "you didn't spend enough money error" */
63 FERR_RESOURCE,
64
65 /* system error (permission denied, etc.) */
66 FERR_SYSTEM,
67
68 /* error return from some external library
69 * (FERR_SYSTEM and FERR_LIBRARY are not strongly distinct) */
70 FERR_LIBRARY,
71 };
72
73 struct ferr {
74 /* code location */
75 const char *file;
76 const char *func;
77 int line;
78
79 enum ferr_kind kind;
80
81 /* unique_id is calculated as a checksum of source filename and error
82 * message format (*before* calling vsnprintf). Line number and
83 * function name are not used; this keeps the number reasonably static
84 * across changes.
85 */
86 uint32_t unique_id;
87
88 char message[384];
89
90 /* valid if != 0. note "errno" might be preprocessor foobar. */
91 int errno_val;
92 /* valid if pathname[0] != '\0' */
93 char pathname[PATH_MAX];
94 };
95
96 /* get error details.
97 *
98 * NB: errval/ferr_r does NOT carry the full error information. It's only
99 * passed around for future API flexibility. ferr_get_last always returns
100 * the last error set in the current thread.
101 */
102 const struct ferr *ferr_get_last(ferr_r errval);
103
104 /* can optionally be called at strategic locations.
105 * always returns 0. */
106 ferr_r ferr_clear(void);
107
108 /* do NOT call these functions directly. only for macro use! */
109 ferr_r ferr_set_internal(const char *file, int line, const char *func,
110 enum ferr_kind kind, const char *text, ...);
111 ferr_r ferr_set_internal_ext(const char *file, int line, const char *func,
112 enum ferr_kind kind, const char *pathname,
113 int errno_val, const char *text, ...);
114
115 #define ferr_ok() 0
116
117 /* Report an error.
118 *
119 * If you need to do cleanup (free memory, etc.), save the return value in a
120 * variable of type ferr_r.
121 *
122 * Don't put a \n at the end of the error message.
123 */
124 #define ferr_code_bug(...) \
125 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CODE_BUG, \
126 __VA_ARGS__)
127 #define ferr_cfg_invalid(...) \
128 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_INVALID, \
129 __VA_ARGS__)
130 #define ferr_cfg_reality(...) \
131 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_CONFIG_REALITY, \
132 __VA_ARGS__)
133 #define ferr_cfg_resource(...) \
134 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_RESOURCE, \
135 __VA_ARGS__)
136 #define ferr_system(...) \
137 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_SYSTEM, \
138 __VA_ARGS__)
139 #define ferr_library(...) \
140 ferr_set_internal(__FILE__, __LINE__, __func__, FERR_LIBRARY, \
141 __VA_ARGS__)
142
143 /* extended information variants */
144 #define ferr_system_errno(...) \
145 ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, NULL, \
146 errno, __VA_ARGS__)
147 #define ferr_system_path_errno(path, ...) \
148 ferr_set_internal_ext(__FILE__, __LINE__, __func__, FERR_SYSTEM, path, \
149 errno, __VA_ARGS__)
150
151 #include "vty.h"
152 /* print error message to vty; $ERR is replaced by the error's message */
153 void vty_print_error(struct vty *vty, ferr_r err, const char *msg, ...);
154
155 #define CMD_FERR_DO(func, action, ...) \
156 do { \
157 ferr_r cmd_retval = func; \
158 if (cmd_retval) { \
159 vty_print_error(vty, cmd_retval, __VA_ARGS__); \
160 action; \
161 } \
162 } while (0)
163
164 #define CMD_FERR_RETURN(func, ...) \
165 CMD_FERR_DO(func, return CMD_WARNING_CONFIG_FAILED, __VA_ARGS__)
166 #define CMD_FERR_GOTO(func, label, ...) \
167 CMD_FERR_DO(func, goto label, __VA_ARGS__)
168
169 /* example: uses bogus #define to keep indent.py happy */
170 #ifdef THIS_IS_AN_EXAMPLE
171 ferr_r foo_bar_set(struct object *obj, int bar)
172 {
173 if (bar < 1 || bar >= 100)
174 return ferr_config_invalid("bar setting (%d) must be 0<x<100",
175 bar);
176 obj->bar = bar;
177 if (ioctl(obj->fd, bar))
178 return ferr_system_errno("couldn't set bar to %d", bar);
179
180 return ferr_ok();
181 }
182
183 DEFUN("bla")
184 {
185 CMD_FERR_RETURN(foo_bar_set(obj, atoi(argv[1])),
186 "command failed: $ERR\n");
187 return CMD_SUCCESS;
188 }
189
190 #endif /* THIS_IS_AN_EXAMPLE */
191
192 #endif /* _FERR_H */