Catalli's threaded switch
[sliver-openvswitch.git] / lib / ovsdb-error.c
1 /* Copyright (c) 2009, 2010 Nicira Networks
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 "dynamic-string.h"
24 #include "json.h"
25 #include "util.h"
26 #include "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 struct ovsdb_error *
118 ovsdb_internal_error(const char *file, int line, const char *details, ...)
119 {
120     struct ds ds = DS_EMPTY_INITIALIZER;
121     struct backtrace backtrace;
122     struct ovsdb_error *error;
123     va_list args;
124
125     ds_put_format(&ds, "%s:%d:", file, line);
126
127     if (details) {
128         ds_put_char(&ds, ' ');
129         va_start(args, details);
130         ds_put_format_valist(&ds, details, args);
131         va_end(args);
132     }
133
134     backtrace_capture(&backtrace);
135     if (backtrace.n_frames) {
136         int i;
137
138         ds_put_cstr(&ds, " (backtrace:");
139         for (i = 0; i < backtrace.n_frames; i++) {
140             ds_put_format(&ds, " 0x%08"PRIxPTR, backtrace.frames[i]);
141         }
142         ds_put_char(&ds, ')');
143     }
144
145     ds_put_format(&ds, " (%s %s%s)", program_name, VERSION, BUILDNR);
146
147     error = ovsdb_error("internal error", "%s", ds_cstr(&ds));
148
149     ds_destroy(&ds);
150
151     return error;
152 }
153
154 void
155 ovsdb_error_destroy(struct ovsdb_error *error)
156 {
157     if (error) {
158         free(error->details);
159         free(error->syntax);
160         free(error);
161     }
162 }
163
164 struct ovsdb_error *
165 ovsdb_error_clone(const struct ovsdb_error *old)
166 {
167     if (old) {
168         struct ovsdb_error *new = xmalloc(sizeof *new);
169         new->tag = old->tag;
170         new->details = old->details ? xstrdup(old->details) : NULL;
171         new->syntax = old->syntax ? xstrdup(old->syntax) : NULL;
172         new->errno_ = old->errno_;
173         return new;
174     } else {
175         return NULL;
176     }
177 }
178
179 static const char *
180 ovsdb_errno_string(int error)
181 {
182     return error == EOF ? "unexpected end of file" : strerror(error);
183 }
184
185 struct json *
186 ovsdb_error_to_json(const struct ovsdb_error *error)
187 {
188     struct json *json = json_object_create();
189     json_object_put_string(json, "error", error->tag);
190     if (error->details) {
191         json_object_put_string(json, "details", error->details);
192     }
193     if (error->syntax) {
194         json_object_put_string(json, "syntax", error->syntax);
195     }
196     if (error->errno_) {
197         json_object_put_string(json, "io-error",
198                                ovsdb_errno_string(error->errno_));
199     }
200     return json;
201 }
202
203 char *
204 ovsdb_error_to_string(const struct ovsdb_error *error)
205 {
206     struct ds ds = DS_EMPTY_INITIALIZER;
207     if (error->syntax) {
208         ds_put_format(&ds, "syntax \"%s\": ", error->syntax);
209     }
210     ds_put_cstr(&ds, error->tag);
211     if (error->details) {
212         ds_put_format(&ds, ": %s", error->details);
213     }
214     if (error->errno_) {
215         ds_put_format(&ds, " (%s)", ovsdb_errno_string(error->errno_));
216     }
217     return ds_steal_cstr(&ds);
218 }
219
220 const char *
221 ovsdb_error_get_tag(const struct ovsdb_error *error)
222 {
223     return error->tag;
224 }
225
226 /* If 'error' is nonnull, logs it as an error and frees it.  To be used in
227  * situations where an error should never occur, but an 'ovsdb_error *' gets
228  * passed back anyhow. */
229 void
230 ovsdb_error_assert(struct ovsdb_error *error)
231 {
232     if (error) {
233         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
234         char *s = ovsdb_error_to_string(error);
235         VLOG_ERR_RL(&rl, "unexpected ovsdb error: %s", s);
236         free(s);
237         ovsdb_error_destroy(error);
238     }
239 }
240