]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ovsdb-error.c
netdev-offload-tc: Use single 'once' variable for probing tc features
[mirror_ovs.git] / lib / ovsdb-error.c
CommitLineData
3865965d 1/* Copyright (c) 2009, 2010, 2011, 2012, 2016, 2017 Nicira, Inc.
f85f8ebb
BP
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"
3e8a2ad1 23#include "openvswitch/dynamic-string.h"
ee89ea7b 24#include "openvswitch/json.h"
f85f8ebb 25#include "util.h"
e6211adc 26#include "openvswitch/vlog.h"
80af01ed 27
d98e6007 28VLOG_DEFINE_THIS_MODULE(ovsdb_error);
f85f8ebb
BP
29
30struct 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
37static struct ovsdb_error *
38ovsdb_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
48struct ovsdb_error *
49ovsdb_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
61struct ovsdb_error *
62ovsdb_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
76struct ovsdb_error *
77ovsdb_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 */
62c87d4a 89 error->syntax = json_to_string(json, JSSF_SORT);
f85f8ebb
BP
90 }
91
92 return error;
93}
94
95struct ovsdb_error *
96ovsdb_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
1dd5b71d
BP
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'. */
f85f8ebb 124struct ovsdb_error *
1dd5b71d
BP
125ovsdb_internal_error(struct ovsdb_error *inner_error,
126 const char *file, int line, const char *details, ...)
f85f8ebb
BP
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
8a07709c 153 ds_put_format(&ds, " (%s %s)", program_name, VERSION);
f85f8ebb 154
1dd5b71d 155 if (inner_error) {
3865965d 156 char *s = ovsdb_error_to_string_free(inner_error);
1dd5b71d
BP
157 ds_put_format(&ds, " (generated from: %s)", s);
158 free(s);
1dd5b71d
BP
159 }
160
f85f8ebb
BP
161 error = ovsdb_error("internal error", "%s", ds_cstr(&ds));
162
163 ds_destroy(&ds);
164
165 return error;
166}
167
d6db7b3c
LR
168struct ovsdb_error *
169ovsdb_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
f85f8ebb
BP
181void
182ovsdb_error_destroy(struct ovsdb_error *error)
183{
184 if (error) {
185 free(error->details);
186 free(error->syntax);
187 free(error);
188 }
189}
190
191struct ovsdb_error *
192ovsdb_error_clone(const struct ovsdb_error *old)
193{
194 if (old) {
195 struct ovsdb_error *new = xmalloc(sizeof *new);
196 new->tag = old->tag;
2225c0b9
BP
197 new->details = nullable_xstrdup(old->details);
198 new->syntax = nullable_xstrdup(old->syntax);
f85f8ebb
BP
199 new->errno_ = old->errno_;
200 return new;
201 } else {
202 return NULL;
203 }
204}
205
201891c3
BP
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()). */
f85f8ebb
BP
208struct json *
209ovsdb_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 }
201891c3
BP
216
217 /* These are RFC 7047-compliant extensions. */
f85f8ebb
BP
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",
fe1e967e 223 ovs_retval_to_string(error->errno_));
f85f8ebb 224 }
201891c3
BP
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'. */
233struct json *
234ovsdb_error_to_json_free(struct ovsdb_error *error)
235{
236 struct json *json = ovsdb_error_to_json(error);
237 ovsdb_error_destroy(error);
f85f8ebb
BP
238 return json;
239}
240
3865965d
BP
241/* Returns 'error' converted to a string suitable for use as an error message.
242 * The caller must free the returned string (with free()). */
f85f8ebb
BP
243char *
244ovsdb_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_) {
fe1e967e 255 ds_put_format(&ds, " (%s)", ovs_retval_to_string(error->errno_));
f85f8ebb
BP
256 }
257 return ds_steal_cstr(&ds);
258}
259
3865965d
BP
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'. */
266char *
267ovsdb_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
f85f8ebb
BP
278const char *
279ovsdb_error_get_tag(const struct ovsdb_error *error)
280{
281 return error->tag;
282}
80af01ed
BP
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. */
287void
288ovsdb_error_assert(struct ovsdb_error *error)
289{
290 if (error) {
291 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
3865965d 292 char *s = ovsdb_error_to_string_free(error);
80af01ed
BP
293 VLOG_ERR_RL(&rl, "unexpected ovsdb error: %s", s);
294 free(s);
80af01ed
BP
295 }
296}