Branch data Line data Source code
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 : 22484 : 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 : 12611 : ovsdb_error_valist(const char *tag, const char *details, va_list args)
39 : : {
40 : 12611 : struct ovsdb_error *error = xmalloc(sizeof *error);
41 [ + + ]: 12611 : error->tag = tag ? tag : "ovsdb error";
42 [ + - ]: 12611 : error->details = details ? xvasprintf(details, args) : NULL;
43 : 12611 : error->syntax = NULL;
44 : 12611 : error->errno_ = 0;
45 : 12611 : return error;
46 : : }
47 : :
48 : : struct ovsdb_error *
49 : 320 : ovsdb_error(const char *tag, const char *details, ...)
50 : : {
51 : : struct ovsdb_error *error;
52 : : va_list args;
53 : :
54 : 320 : va_start(args, details);
55 : 320 : error = ovsdb_error_valist(tag, details, args);
56 : 320 : va_end(args);
57 : :
58 : 320 : return error;
59 : : }
60 : :
61 : : struct ovsdb_error *
62 : 3 : ovsdb_io_error(int errno_, const char *details, ...)
63 : : {
64 : : struct ovsdb_error *error;
65 : : va_list args;
66 : :
67 : 3 : va_start(args, details);
68 : 3 : error = ovsdb_error_valist("I/O error", details, args);
69 : 3 : va_end(args);
70 : :
71 : 3 : error->errno_ = errno_;
72 : :
73 : 3 : return error;
74 : : }
75 : :
76 : : struct ovsdb_error *
77 : 12288 : 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 : 12288 : va_start(args, details);
84 [ + + ]: 12288 : error = ovsdb_error_valist(tag ? tag : "syntax error", details, args);
85 : 12288 : va_end(args);
86 : :
87 [ + + ]: 12288 : if (json) {
88 : : /* XXX this is much too much information in some cases */
89 : 12281 : error->syntax = json_to_string(json, JSSF_SORT);
90 : : }
91 : :
92 : 12288 : return error;
93 : : }
94 : :
95 : : struct ovsdb_error *
96 : 0 : ovsdb_wrap_error(struct ovsdb_error *error, const char *details, ...)
97 : : {
98 : : va_list args;
99 : : char *msg;
100 : :
101 : 0 : va_start(args, details);
102 : 0 : msg = xvasprintf(details, args);
103 : 0 : va_end(args);
104 : :
105 [ # # ]: 0 : if (error->details) {
106 : 0 : char *new = xasprintf("%s: %s", msg, error->details);
107 : 0 : free(error->details);
108 : 0 : error->details = new;
109 : 0 : free(msg);
110 : : } else {
111 : 0 : error->details = msg;
112 : : }
113 : :
114 : 0 : 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 : 0 : ovsdb_internal_error(struct ovsdb_error *inner_error,
126 : : const char *file, int line, const char *details, ...)
127 : : {
128 : 0 : struct ds ds = DS_EMPTY_INITIALIZER;
129 : : struct backtrace backtrace;
130 : : struct ovsdb_error *error;
131 : : va_list args;
132 : :
133 : 0 : ds_put_format(&ds, "%s:%d:", file, line);
134 : :
135 [ # # ]: 0 : if (details) {
136 : 0 : ds_put_char(&ds, ' ');
137 : 0 : va_start(args, details);
138 : 0 : ds_put_format_valist(&ds, details, args);
139 : 0 : va_end(args);
140 : : }
141 : :
142 : 0 : backtrace_capture(&backtrace);
143 [ # # ]: 0 : if (backtrace.n_frames) {
144 : : int i;
145 : :
146 : 0 : ds_put_cstr(&ds, " (backtrace:");
147 [ # # ]: 0 : for (i = 0; i < backtrace.n_frames; i++) {
148 : 0 : ds_put_format(&ds, " 0x%08"PRIxPTR, backtrace.frames[i]);
149 : : }
150 : 0 : ds_put_char(&ds, ')');
151 : : }
152 : :
153 : 0 : ds_put_format(&ds, " (%s %s)", program_name, VERSION);
154 : :
155 [ # # ]: 0 : if (inner_error) {
156 : 0 : char *s = ovsdb_error_to_string(inner_error);
157 : 0 : ds_put_format(&ds, " (generated from: %s)", s);
158 : 0 : free(s);
159 : :
160 : 0 : ovsdb_error_destroy(inner_error);
161 : : }
162 : :
163 : 0 : error = ovsdb_error("internal error", "%s", ds_cstr(&ds));
164 : :
165 : 0 : ds_destroy(&ds);
166 : :
167 : 0 : return error;
168 : : }
169 : :
170 : : void
171 : 27789 : ovsdb_error_destroy(struct ovsdb_error *error)
172 : : {
173 [ + + ]: 27789 : if (error) {
174 : 12618 : free(error->details);
175 : 12618 : free(error->syntax);
176 : 12618 : free(error);
177 : : }
178 : 27789 : }
179 : :
180 : : struct ovsdb_error *
181 : 1531 : ovsdb_error_clone(const struct ovsdb_error *old)
182 : : {
183 [ + + ]: 1531 : if (old) {
184 : 7 : struct ovsdb_error *new = xmalloc(sizeof *new);
185 : 7 : new->tag = old->tag;
186 : 7 : new->details = nullable_xstrdup(old->details);
187 : 7 : new->syntax = nullable_xstrdup(old->syntax);
188 : 7 : new->errno_ = old->errno_;
189 : 7 : return new;
190 : : } else {
191 : 1524 : return NULL;
192 : : }
193 : : }
194 : :
195 : : struct json *
196 : 240 : ovsdb_error_to_json(const struct ovsdb_error *error)
197 : : {
198 : 240 : struct json *json = json_object_create();
199 : 240 : json_object_put_string(json, "error", error->tag);
200 [ + - ]: 240 : if (error->details) {
201 : 240 : json_object_put_string(json, "details", error->details);
202 : : }
203 [ + + ]: 240 : if (error->syntax) {
204 : 32 : json_object_put_string(json, "syntax", error->syntax);
205 : : }
206 [ - + ]: 240 : if (error->errno_) {
207 : 0 : json_object_put_string(json, "io-error",
208 : : ovs_retval_to_string(error->errno_));
209 : : }
210 : 240 : return json;
211 : : }
212 : :
213 : : char *
214 : 178 : ovsdb_error_to_string(const struct ovsdb_error *error)
215 : : {
216 : 178 : struct ds ds = DS_EMPTY_INITIALIZER;
217 [ + + ]: 178 : if (error->syntax) {
218 : 68 : ds_put_format(&ds, "syntax \"%s\": ", error->syntax);
219 : : }
220 : 178 : ds_put_cstr(&ds, error->tag);
221 [ + - ]: 178 : if (error->details) {
222 : 178 : ds_put_format(&ds, ": %s", error->details);
223 : : }
224 [ + + ]: 178 : if (error->errno_) {
225 : 3 : ds_put_format(&ds, " (%s)", ovs_retval_to_string(error->errno_));
226 : : }
227 : 178 : return ds_steal_cstr(&ds);
228 : : }
229 : :
230 : : const char *
231 : 98 : ovsdb_error_get_tag(const struct ovsdb_error *error)
232 : : {
233 : 98 : 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 : 27809 : ovsdb_error_assert(struct ovsdb_error *error)
241 : : {
242 [ - + ]: 27809 : if (error) {
243 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
244 : 0 : char *s = ovsdb_error_to_string(error);
245 [ # # ]: 0 : VLOG_ERR_RL(&rl, "unexpected ovsdb error: %s", s);
246 : 0 : free(s);
247 : 0 : ovsdb_error_destroy(error);
248 : : }
249 : 27809 : }
|