Don't go beyond buffer length when printing descriptions
[openvswitch] / lib / ovsdb-error.c
1 /* Copyright (c) 2009 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
27 struct ovsdb_error {
28     const char *tag;            /* String for "error" member. */
29     char *details;              /* String for "details" member. */
30     char *syntax;               /* String for "syntax" member. */
31     int errno_;                 /* Unix errno value, 0 if none. */
32 };
33
34 static struct ovsdb_error *
35 ovsdb_error_valist(const char *tag, const char *details, va_list args)
36 {
37     struct ovsdb_error *error = xmalloc(sizeof *error);
38     error->tag = tag ? tag : "ovsdb error";
39     error->details = details ? xvasprintf(details, args) : NULL;
40     error->syntax = NULL;
41     error->errno_ = 0;
42     return error;
43 }
44
45 struct ovsdb_error *
46 ovsdb_error(const char *tag, const char *details, ...)
47 {
48     struct ovsdb_error *error;
49     va_list args;
50
51     va_start(args, details);
52     error = ovsdb_error_valist(tag, details, args);
53     va_end(args);
54
55     return error;
56 }
57
58 struct ovsdb_error *
59 ovsdb_io_error(int errno_, const char *details, ...)
60 {
61     struct ovsdb_error *error;
62     va_list args;
63
64     va_start(args, details);
65     error = ovsdb_error_valist("I/O error", details, args);
66     va_end(args);
67
68     error->errno_ = errno_;
69
70     return error;
71 }
72
73 struct ovsdb_error *
74 ovsdb_syntax_error(const struct json *json, const char *tag,
75                    const char *details, ...)
76 {
77     struct ovsdb_error *error;
78     va_list args;
79
80     va_start(args, details);
81     error = ovsdb_error_valist(tag ? tag : "syntax error", details, args);
82     va_end(args);
83
84     if (json) {
85         /* XXX this is much too much information in some cases */
86         error->syntax = json_to_string(json, 0);
87     }
88
89     return error;
90 }
91
92 struct ovsdb_error *
93 ovsdb_wrap_error(struct ovsdb_error *error, const char *details, ...)
94 {
95     va_list args;
96     char *msg;
97
98     va_start(args, details);
99     msg = xvasprintf(details, args);
100     va_end(args);
101
102     if (error->details) {
103         char *new = xasprintf("%s: %s", msg, error->details);
104         free(error->details);
105         error->details = new;
106         free(msg);
107     } else {
108         error->details = msg;
109     }
110
111     return error;
112 }
113
114 struct ovsdb_error *
115 ovsdb_internal_error(const char *file, int line, const char *details, ...)
116 {
117     struct ds ds = DS_EMPTY_INITIALIZER;
118     struct backtrace backtrace;
119     struct ovsdb_error *error;
120     va_list args;
121
122     ds_put_format(&ds, "%s:%d:", file, line);
123
124     if (details) {
125         ds_put_char(&ds, ' ');
126         va_start(args, details);
127         ds_put_format_valist(&ds, details, args);
128         va_end(args);
129     }
130
131     backtrace_capture(&backtrace);
132     if (backtrace.n_frames) {
133         int i;
134
135         ds_put_cstr(&ds, " (backtrace:");
136         for (i = 0; i < backtrace.n_frames; i++) {
137             ds_put_format(&ds, " 0x%08"PRIxPTR, backtrace.frames[i]);
138         }
139         ds_put_char(&ds, ')');
140     }
141
142     ds_put_format(&ds, " (%s %s%s)", program_name, VERSION, BUILDNR);
143
144     error = ovsdb_error("internal error", "%s", ds_cstr(&ds));
145
146     ds_destroy(&ds);
147
148     return error;
149 }
150
151 void
152 ovsdb_error_destroy(struct ovsdb_error *error)
153 {
154     if (error) {
155         free(error->details);
156         free(error->syntax);
157         free(error);
158     }
159 }
160
161 struct ovsdb_error *
162 ovsdb_error_clone(const struct ovsdb_error *old)
163 {
164     if (old) {
165         struct ovsdb_error *new = xmalloc(sizeof *new);
166         new->tag = old->tag;
167         new->details = old->details ? xstrdup(old->details) : NULL;
168         new->syntax = old->syntax ? xstrdup(old->syntax) : NULL;
169         new->errno_ = old->errno_;
170         return new;
171     } else {
172         return NULL;
173     }
174 }
175
176 static const char *
177 ovsdb_errno_string(int error)
178 {
179     return error == EOF ? "unexpected end of file" : strerror(error);
180 }
181
182 struct json *
183 ovsdb_error_to_json(const struct ovsdb_error *error)
184 {
185     struct json *json = json_object_create();
186     json_object_put_string(json, "error", error->tag);
187     if (error->details) {
188         json_object_put_string(json, "details", error->details);
189     }
190     if (error->syntax) {
191         json_object_put_string(json, "syntax", error->syntax);
192     }
193     if (error->errno_) {
194         json_object_put_string(json, "io-error",
195                                ovsdb_errno_string(error->errno_));
196     }
197     return json;
198 }
199
200 char *
201 ovsdb_error_to_string(const struct ovsdb_error *error)
202 {
203     struct ds ds = DS_EMPTY_INITIALIZER;
204     if (error->syntax) {
205         ds_put_format(&ds, "syntax \"%s\": ", error->syntax);
206     }
207     ds_put_cstr(&ds, error->tag);
208     if (error->details) {
209         ds_put_format(&ds, ": %s", error->details);
210     }
211     if (error->errno_) {
212         ds_put_format(&ds, " (%s)", ovsdb_errno_string(error->errno_));
213     }
214     return ds_steal_cstr(&ds);
215 }
216
217 const char *
218 ovsdb_error_get_tag(const struct ovsdb_error *error)
219 {
220     return error->tag;
221 }