]> git.proxmox.com Git - ovs.git/blob - lib/ovsdb-error.c
ovsdb: Prevent OVSDB server from replicating itself.
[ovs.git] / lib / ovsdb-error.c
1 /* Copyright (c) 2009, 2010, 2011, 2012, 2016 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(inner_error);
157 ds_put_format(&ds, " (generated from: %s)", s);
158 free(s);
159
160 ovsdb_error_destroy(inner_error);
161 }
162
163 error = ovsdb_error("internal error", "%s", ds_cstr(&ds));
164
165 ds_destroy(&ds);
166
167 return error;
168 }
169
170 void
171 ovsdb_error_destroy(struct ovsdb_error *error)
172 {
173 if (error) {
174 free(error->details);
175 free(error->syntax);
176 free(error);
177 }
178 }
179
180 struct ovsdb_error *
181 ovsdb_error_clone(const struct ovsdb_error *old)
182 {
183 if (old) {
184 struct ovsdb_error *new = xmalloc(sizeof *new);
185 new->tag = old->tag;
186 new->details = nullable_xstrdup(old->details);
187 new->syntax = nullable_xstrdup(old->syntax);
188 new->errno_ = old->errno_;
189 return new;
190 } else {
191 return NULL;
192 }
193 }
194
195 struct json *
196 ovsdb_error_to_json(const struct ovsdb_error *error)
197 {
198 struct json *json = json_object_create();
199 json_object_put_string(json, "error", error->tag);
200 if (error->details) {
201 json_object_put_string(json, "details", error->details);
202 }
203 if (error->syntax) {
204 json_object_put_string(json, "syntax", error->syntax);
205 }
206 if (error->errno_) {
207 json_object_put_string(json, "io-error",
208 ovs_retval_to_string(error->errno_));
209 }
210 return json;
211 }
212
213 char *
214 ovsdb_error_to_string(const struct ovsdb_error *error)
215 {
216 struct ds ds = DS_EMPTY_INITIALIZER;
217 if (error->syntax) {
218 ds_put_format(&ds, "syntax \"%s\": ", error->syntax);
219 }
220 ds_put_cstr(&ds, error->tag);
221 if (error->details) {
222 ds_put_format(&ds, ": %s", error->details);
223 }
224 if (error->errno_) {
225 ds_put_format(&ds, " (%s)", ovs_retval_to_string(error->errno_));
226 }
227 return ds_steal_cstr(&ds);
228 }
229
230 const char *
231 ovsdb_error_get_tag(const struct ovsdb_error *error)
232 {
233 return error->tag;
234 }
235
236 /* If 'error' is nonnull, logs it as an error and frees it. To be used in
237 * situations where an error should never occur, but an 'ovsdb_error *' gets
238 * passed back anyhow. */
239 void
240 ovsdb_error_assert(struct ovsdb_error *error)
241 {
242 if (error) {
243 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
244 char *s = ovsdb_error_to_string(error);
245 VLOG_ERR_RL(&rl, "unexpected ovsdb error: %s", s);
246 free(s);
247 ovsdb_error_destroy(error);
248 }
249 }