]> git.proxmox.com Git - ovs.git/blob - lib/ovsdb-error.c
ovsdb: add support for role-based access controls
[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 struct ovsdb_error *
171 ovsdb_perm_error(const char *details, ...)
172 {
173 struct ovsdb_error *error;
174 va_list args;
175
176 va_start(args, details);
177 error = ovsdb_error_valist("permission error", details, args);
178 va_end(args);
179
180 return error;
181 }
182
183 void
184 ovsdb_error_destroy(struct ovsdb_error *error)
185 {
186 if (error) {
187 free(error->details);
188 free(error->syntax);
189 free(error);
190 }
191 }
192
193 struct ovsdb_error *
194 ovsdb_error_clone(const struct ovsdb_error *old)
195 {
196 if (old) {
197 struct ovsdb_error *new = xmalloc(sizeof *new);
198 new->tag = old->tag;
199 new->details = nullable_xstrdup(old->details);
200 new->syntax = nullable_xstrdup(old->syntax);
201 new->errno_ = old->errno_;
202 return new;
203 } else {
204 return NULL;
205 }
206 }
207
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 if (error->syntax) {
217 json_object_put_string(json, "syntax", error->syntax);
218 }
219 if (error->errno_) {
220 json_object_put_string(json, "io-error",
221 ovs_retval_to_string(error->errno_));
222 }
223 return json;
224 }
225
226 char *
227 ovsdb_error_to_string(const struct ovsdb_error *error)
228 {
229 struct ds ds = DS_EMPTY_INITIALIZER;
230 if (error->syntax) {
231 ds_put_format(&ds, "syntax \"%s\": ", error->syntax);
232 }
233 ds_put_cstr(&ds, error->tag);
234 if (error->details) {
235 ds_put_format(&ds, ": %s", error->details);
236 }
237 if (error->errno_) {
238 ds_put_format(&ds, " (%s)", ovs_retval_to_string(error->errno_));
239 }
240 return ds_steal_cstr(&ds);
241 }
242
243 const char *
244 ovsdb_error_get_tag(const struct ovsdb_error *error)
245 {
246 return error->tag;
247 }
248
249 /* If 'error' is nonnull, logs it as an error and frees it. To be used in
250 * situations where an error should never occur, but an 'ovsdb_error *' gets
251 * passed back anyhow. */
252 void
253 ovsdb_error_assert(struct ovsdb_error *error)
254 {
255 if (error) {
256 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
257 char *s = ovsdb_error_to_string(error);
258 VLOG_ERR_RL(&rl, "unexpected ovsdb error: %s", s);
259 free(s);
260 ovsdb_error_destroy(error);
261 }
262 }