]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ovsdb-error.c
ovsdb-idl: Fix iteration over tracked rows with no actual data.
[mirror_ovs.git] / lib / ovsdb-error.c
1 /* Copyright (c) 2009, 2010, 2011, 2012, 2016, 2017 Nicira, Inc.
2 *
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 #include <config.h>
17
18 #include "ovsdb-error.h"
19
20 #include <inttypes.h>
21
22 #include "backtrace.h"
23 #include "openvswitch/dynamic-string.h"
24 #include "openvswitch/json.h"
25 #include "util.h"
26 #include "openvswitch/vlog.h"
27
28 VLOG_DEFINE_THIS_MODULE(ovsdb_error);
29
30 struct ovsdb_error {
31 const char *tag; /* String for "error" member. */
32 char *details; /* String for "details" member. */
33 char *syntax; /* String for "syntax" member. */
34 int errno_; /* Unix errno value, 0 if none. */
35 };
36
37 static struct ovsdb_error *
38 ovsdb_error_valist(const char *tag, const char *details, va_list args)
39 {
40 struct ovsdb_error *error = xmalloc(sizeof *error);
41 error->tag = tag ? tag : "ovsdb error";
42 error->details = details ? xvasprintf(details, args) : NULL;
43 error->syntax = NULL;
44 error->errno_ = 0;
45 return error;
46 }
47
48 struct ovsdb_error *
49 ovsdb_error(const char *tag, const char *details, ...)
50 {
51 struct ovsdb_error *error;
52 va_list args;
53
54 va_start(args, details);
55 error = ovsdb_error_valist(tag, details, args);
56 va_end(args);
57
58 return error;
59 }
60
61 struct ovsdb_error *
62 ovsdb_io_error(int errno_, const char *details, ...)
63 {
64 struct ovsdb_error *error;
65 va_list args;
66
67 va_start(args, details);
68 error = ovsdb_error_valist("I/O error", details, args);
69 va_end(args);
70
71 error->errno_ = errno_;
72
73 return error;
74 }
75
76 struct ovsdb_error *
77 ovsdb_syntax_error(const struct json *json, const char *tag,
78 const char *details, ...)
79 {
80 struct ovsdb_error *error;
81 va_list args;
82
83 va_start(args, details);
84 error = ovsdb_error_valist(tag ? tag : "syntax error", details, args);
85 va_end(args);
86
87 if (json) {
88 /* XXX this is much too much information in some cases */
89 error->syntax = json_to_string(json, JSSF_SORT);
90 }
91
92 return error;
93 }
94
95 struct ovsdb_error *
96 ovsdb_wrap_error(struct ovsdb_error *error, const char *details, ...)
97 {
98 va_list args;
99 char *msg;
100
101 va_start(args, details);
102 msg = xvasprintf(details, args);
103 va_end(args);
104
105 if (error->details) {
106 char *new = xasprintf("%s: %s", msg, error->details);
107 free(error->details);
108 error->details = new;
109 free(msg);
110 } else {
111 error->details = msg;
112 }
113
114 return error;
115 }
116
117 /* Returns an ovsdb_error that represents an internal error for file name
118 * 'file' and line number 'line', with 'details' (formatted as with printf())
119 * as the associated message. The caller is responsible for freeing the
120 * returned error.
121 *
122 * If 'inner_error' is nonnull then the returned error is wrapped around
123 * 'inner_error'. Takes ownership of 'inner_error'. */
124 struct ovsdb_error *
125 ovsdb_internal_error(struct ovsdb_error *inner_error,
126 const char *file, int line, const char *details, ...)
127 {
128 struct ds ds = DS_EMPTY_INITIALIZER;
129 struct backtrace backtrace;
130 struct ovsdb_error *error;
131 va_list args;
132
133 ds_put_format(&ds, "%s:%d:", file, line);
134
135 if (details) {
136 ds_put_char(&ds, ' ');
137 va_start(args, details);
138 ds_put_format_valist(&ds, details, args);
139 va_end(args);
140 }
141
142 backtrace_capture(&backtrace);
143 if (backtrace.n_frames) {
144 int i;
145
146 ds_put_cstr(&ds, " (backtrace:");
147 for (i = 0; i < backtrace.n_frames; i++) {
148 ds_put_format(&ds, " 0x%08"PRIxPTR, backtrace.frames[i]);
149 }
150 ds_put_char(&ds, ')');
151 }
152
153 ds_put_format(&ds, " (%s %s)", program_name, VERSION);
154
155 if (inner_error) {
156 char *s = ovsdb_error_to_string_free(inner_error);
157 ds_put_format(&ds, " (generated from: %s)", s);
158 free(s);
159 }
160
161 error = ovsdb_error("internal error", "%s", ds_cstr(&ds));
162
163 ds_destroy(&ds);
164
165 return error;
166 }
167
168 struct ovsdb_error *
169 ovsdb_perm_error(const char *details, ...)
170 {
171 struct ovsdb_error *error;
172 va_list args;
173
174 va_start(args, details);
175 error = ovsdb_error_valist("permission error", details, args);
176 va_end(args);
177
178 return error;
179 }
180
181 void
182 ovsdb_error_destroy(struct ovsdb_error *error)
183 {
184 if (error) {
185 free(error->details);
186 free(error->syntax);
187 free(error);
188 }
189 }
190
191 struct ovsdb_error *
192 ovsdb_error_clone(const struct ovsdb_error *old)
193 {
194 if (old) {
195 struct ovsdb_error *new = xmalloc(sizeof *new);
196 new->tag = old->tag;
197 new->details = nullable_xstrdup(old->details);
198 new->syntax = nullable_xstrdup(old->syntax);
199 new->errno_ = old->errno_;
200 return new;
201 } else {
202 return NULL;
203 }
204 }
205
206 /* Returns 'error' converted to the <error> JSON object format described in RFC
207 * 7047. The caller must free the returned json (with json_destroy()). */
208 struct json *
209 ovsdb_error_to_json(const struct ovsdb_error *error)
210 {
211 struct json *json = json_object_create();
212 json_object_put_string(json, "error", error->tag);
213 if (error->details) {
214 json_object_put_string(json, "details", error->details);
215 }
216
217 /* These are RFC 7047-compliant extensions. */
218 if (error->syntax) {
219 json_object_put_string(json, "syntax", error->syntax);
220 }
221 if (error->errno_) {
222 json_object_put_string(json, "io-error",
223 ovs_retval_to_string(error->errno_));
224 }
225
226 return json;
227 }
228
229 /* Returns 'error' converted to the <error> JSON object format described in RFC
230 * 7047. The caller must free the returned json (with json_destroy()).
231 *
232 * Also, frees 'error'. */
233 struct json *
234 ovsdb_error_to_json_free(struct ovsdb_error *error)
235 {
236 struct json *json = ovsdb_error_to_json(error);
237 ovsdb_error_destroy(error);
238 return json;
239 }
240
241 /* Returns 'error' converted to a string suitable for use as an error message.
242 * The caller must free the returned string (with free()). */
243 char *
244 ovsdb_error_to_string(const struct ovsdb_error *error)
245 {
246 struct ds ds = DS_EMPTY_INITIALIZER;
247 if (error->syntax) {
248 ds_put_format(&ds, "syntax \"%s\": ", error->syntax);
249 }
250 ds_put_cstr(&ds, error->tag);
251 if (error->details) {
252 ds_put_format(&ds, ": %s", error->details);
253 }
254 if (error->errno_) {
255 ds_put_format(&ds, " (%s)", ovs_retval_to_string(error->errno_));
256 }
257 return ds_steal_cstr(&ds);
258 }
259
260 /* Returns 'error' converted to a string suitable for use as an error message.
261 * The caller must free the returned string (with free()).
262 *
263 * If 'error' is NULL, returns NULL.
264 *
265 * Also, frees 'error'. */
266 char *
267 ovsdb_error_to_string_free(struct ovsdb_error *error)
268 {
269 if (error) {
270 char *s = ovsdb_error_to_string(error);
271 ovsdb_error_destroy(error);
272 return s;
273 } else {
274 return NULL;
275 }
276 }
277
278 const char *
279 ovsdb_error_get_tag(const struct ovsdb_error *error)
280 {
281 return error->tag;
282 }
283
284 /* If 'error' is nonnull, logs it as an error and frees it. To be used in
285 * situations where an error should never occur, but an 'ovsdb_error *' gets
286 * passed back anyhow. */
287 void
288 ovsdb_error_assert(struct ovsdb_error *error)
289 {
290 if (error) {
291 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
292 char *s = ovsdb_error_to_string_free(error);
293 VLOG_ERR_RL(&rl, "unexpected ovsdb error: %s", s);
294 free(s);
295 }
296 }