]>
Commit | Line | Data |
---|---|---|
2225c0b9 | 1 | /* Copyright (c) 2009, 2010, 2011, 2012, 2016 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 | 28 | VLOG_DEFINE_THIS_MODULE(ovsdb_error); |
f85f8ebb BP |
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 */ | |
62c87d4a | 89 | error->syntax = json_to_string(json, JSSF_SORT); |
f85f8ebb BP |
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 | ||
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 | 124 | struct ovsdb_error * |
1dd5b71d BP |
125 | ovsdb_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 BP |
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 | ||
f85f8ebb BP |
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; | |
2225c0b9 BP |
186 | new->details = nullable_xstrdup(old->details); |
187 | new->syntax = nullable_xstrdup(old->syntax); | |
f85f8ebb BP |
188 | new->errno_ = old->errno_; |
189 | return new; | |
190 | } else { | |
191 | return NULL; | |
192 | } | |
193 | } | |
194 | ||
f85f8ebb BP |
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", | |
fe1e967e | 208 | ovs_retval_to_string(error->errno_)); |
f85f8ebb BP |
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_) { | |
fe1e967e | 225 | ds_put_format(&ds, " (%s)", ovs_retval_to_string(error->errno_)); |
f85f8ebb BP |
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 | } | |
80af01ed BP |
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 | } |