]>
Commit | Line | Data |
---|---|---|
d5ec4f27 LC |
1 | /* |
2 | * QEMU Error Objects | |
3 | * | |
4 | * Copyright IBM, Corp. 2011 | |
a29a37b9 | 5 | * Copyright (C) 2011-2015 Red Hat, Inc. |
d5ec4f27 LC |
6 | * |
7 | * Authors: | |
8 | * Anthony Liguori <aliguori@us.ibm.com> | |
a29a37b9 | 9 | * Markus Armbruster <armbru@redhat.com>, |
d5ec4f27 LC |
10 | * |
11 | * This work is licensed under the terms of the GNU LGPL, version 2. See | |
12 | * the COPYING.LIB file in the top-level directory. | |
13 | */ | |
e4ea5e2d | 14 | |
aafd7584 | 15 | #include "qemu/osdep.h" |
da34e65c | 16 | #include "qapi/error.h" |
073a3411 | 17 | #include "qemu/error-report.h" |
d5ec4f27 LC |
18 | |
19 | struct Error | |
20 | { | |
d5ec4f27 | 21 | char *msg; |
13f59ae8 | 22 | ErrorClass err_class; |
1e9b65bb MA |
23 | const char *src, *func; |
24 | int line; | |
50b7b000 | 25 | GString *hint; |
d5ec4f27 LC |
26 | }; |
27 | ||
5d24ee70 | 28 | Error *error_abort; |
a29a37b9 | 29 | Error *error_fatal; |
3ffef1a5 | 30 | Error *error_warn; |
5d24ee70 | 31 | |
3ffef1a5 | 32 | static void error_handle(Error **errp, Error *err) |
1e9b65bb | 33 | { |
a29a37b9 MA |
34 | if (errp == &error_abort) { |
35 | fprintf(stderr, "Unexpected error in %s() at %s:%d:\n", | |
36 | err->func, err->src, err->line); | |
b922c050 VSO |
37 | error_report("%s", error_get_pretty(err)); |
38 | if (err->hint) { | |
39 | error_printf("%s", err->hint->str); | |
40 | } | |
a29a37b9 MA |
41 | abort(); |
42 | } | |
43 | if (errp == &error_fatal) { | |
44 | error_report_err(err); | |
45 | exit(1); | |
46 | } | |
3ffef1a5 MAL |
47 | if (errp == &error_warn) { |
48 | warn_report_err(err); | |
cc40b8b8 SB |
49 | } else if (errp && !*errp) { |
50 | *errp = err; | |
51 | } else { | |
52 | error_free(err); | |
3ffef1a5 | 53 | } |
1e9b65bb MA |
54 | } |
55 | ||
beede7e8 | 56 | G_GNUC_PRINTF(6, 0) |
1e9b65bb MA |
57 | static void error_setv(Error **errp, |
58 | const char *src, int line, const char *func, | |
20e2dec1 DB |
59 | ErrorClass err_class, const char *fmt, va_list ap, |
60 | const char *suffix) | |
d5ec4f27 LC |
61 | { |
62 | Error *err; | |
b276d249 | 63 | int saved_errno = errno; |
d5ec4f27 LC |
64 | |
65 | if (errp == NULL) { | |
66 | return; | |
67 | } | |
d195325b | 68 | assert(*errp == NULL); |
d5ec4f27 | 69 | |
7267c094 | 70 | err = g_malloc0(sizeof(*err)); |
df1e608a | 71 | err->msg = g_strdup_vprintf(fmt, ap); |
20e2dec1 DB |
72 | if (suffix) { |
73 | char *msg = err->msg; | |
74 | err->msg = g_strdup_printf("%s: %s", msg, suffix); | |
75 | g_free(msg); | |
76 | } | |
13f59ae8 | 77 | err->err_class = err_class; |
1e9b65bb MA |
78 | err->src = src; |
79 | err->line = line; | |
80 | err->func = func; | |
d5ec4f27 | 81 | |
3ffef1a5 | 82 | error_handle(errp, err); |
b276d249 HR |
83 | |
84 | errno = saved_errno; | |
d5ec4f27 LC |
85 | } |
86 | ||
1e9b65bb MA |
87 | void error_set_internal(Error **errp, |
88 | const char *src, int line, const char *func, | |
89 | ErrorClass err_class, const char *fmt, ...) | |
55237508 MA |
90 | { |
91 | va_list ap; | |
92 | ||
93 | va_start(ap, fmt); | |
20e2dec1 | 94 | error_setv(errp, src, line, func, err_class, fmt, ap, NULL); |
55237508 MA |
95 | va_end(ap); |
96 | } | |
97 | ||
1e9b65bb MA |
98 | void error_setg_internal(Error **errp, |
99 | const char *src, int line, const char *func, | |
100 | const char *fmt, ...) | |
a9499ddd MA |
101 | { |
102 | va_list ap; | |
103 | ||
104 | va_start(ap, fmt); | |
20e2dec1 | 105 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap, NULL); |
a9499ddd MA |
106 | va_end(ap); |
107 | } | |
108 | ||
1e9b65bb MA |
109 | void error_setg_errno_internal(Error **errp, |
110 | const char *src, int line, const char *func, | |
111 | int os_errno, const char *fmt, ...) | |
680d16dc | 112 | { |
680d16dc | 113 | va_list ap; |
b276d249 | 114 | int saved_errno = errno; |
680d16dc | 115 | |
680d16dc | 116 | va_start(ap, fmt); |
20e2dec1 DB |
117 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap, |
118 | os_errno != 0 ? strerror(os_errno) : NULL); | |
680d16dc | 119 | va_end(ap); |
680d16dc | 120 | |
b276d249 | 121 | errno = saved_errno; |
680d16dc PB |
122 | } |
123 | ||
1e9b65bb MA |
124 | void error_setg_file_open_internal(Error **errp, |
125 | const char *src, int line, const char *func, | |
126 | int os_errno, const char *filename) | |
54028d75 | 127 | { |
1e9b65bb MA |
128 | error_setg_errno_internal(errp, src, line, func, os_errno, |
129 | "Could not open '%s'", filename); | |
54028d75 LC |
130 | } |
131 | ||
49fbc723 | 132 | void error_vprepend(Error *const *errp, const char *fmt, va_list ap) |
8277d2aa MA |
133 | { |
134 | GString *newmsg; | |
135 | ||
136 | if (!errp) { | |
137 | return; | |
138 | } | |
139 | ||
140 | newmsg = g_string_new(NULL); | |
141 | g_string_vprintf(newmsg, fmt, ap); | |
142 | g_string_append(newmsg, (*errp)->msg); | |
536eeea8 | 143 | g_free((*errp)->msg); |
8277d2aa MA |
144 | (*errp)->msg = g_string_free(newmsg, 0); |
145 | } | |
146 | ||
49fbc723 | 147 | void error_prepend(Error *const *errp, const char *fmt, ...) |
8277d2aa MA |
148 | { |
149 | va_list ap; | |
150 | ||
151 | va_start(ap, fmt); | |
152 | error_vprepend(errp, fmt, ap); | |
153 | va_end(ap); | |
154 | } | |
155 | ||
49fbc723 | 156 | void error_append_hint(Error *const *errp, const char *fmt, ...) |
50b7b000 EB |
157 | { |
158 | va_list ap; | |
159 | int saved_errno = errno; | |
160 | Error *err; | |
161 | ||
162 | if (!errp) { | |
163 | return; | |
164 | } | |
165 | err = *errp; | |
f4d0064a | 166 | assert(err && errp != &error_abort && errp != &error_fatal); |
50b7b000 EB |
167 | |
168 | if (!err->hint) { | |
169 | err->hint = g_string_new(NULL); | |
170 | } | |
171 | va_start(ap, fmt); | |
172 | g_string_append_vprintf(err->hint, fmt, ap); | |
173 | va_end(ap); | |
174 | ||
175 | errno = saved_errno; | |
176 | } | |
177 | ||
20840d4c TS |
178 | #ifdef _WIN32 |
179 | ||
1e9b65bb MA |
180 | void error_setg_win32_internal(Error **errp, |
181 | const char *src, int line, const char *func, | |
182 | int win32_err, const char *fmt, ...) | |
20840d4c | 183 | { |
20840d4c | 184 | va_list ap; |
20e2dec1 | 185 | char *suffix = NULL; |
20840d4c TS |
186 | |
187 | if (errp == NULL) { | |
188 | return; | |
189 | } | |
20840d4c | 190 | |
20e2dec1 DB |
191 | if (win32_err != 0) { |
192 | suffix = g_win32_error_message(win32_err); | |
193 | } | |
194 | ||
20840d4c | 195 | va_start(ap, fmt); |
20e2dec1 DB |
196 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, |
197 | fmt, ap, suffix); | |
55237508 MA |
198 | va_end(ap); |
199 | ||
20e2dec1 | 200 | g_free(suffix); |
20840d4c TS |
201 | } |
202 | ||
203 | #endif | |
204 | ||
79020cfc LC |
205 | Error *error_copy(const Error *err) |
206 | { | |
207 | Error *err_new; | |
208 | ||
209 | err_new = g_malloc0(sizeof(*err)); | |
210 | err_new->msg = g_strdup(err->msg); | |
13f59ae8 | 211 | err_new->err_class = err->err_class; |
88e2ce29 EB |
212 | err_new->src = err->src; |
213 | err_new->line = err->line; | |
214 | err_new->func = err->func; | |
50b7b000 EB |
215 | if (err->hint) { |
216 | err_new->hint = g_string_new(err->hint->str); | |
217 | } | |
79020cfc LC |
218 | |
219 | return err_new; | |
220 | } | |
221 | ||
ea25fbca LC |
222 | ErrorClass error_get_class(const Error *err) |
223 | { | |
224 | return err->err_class; | |
225 | } | |
226 | ||
d59ce6f3 | 227 | const char *error_get_pretty(const Error *err) |
d5ec4f27 | 228 | { |
d5ec4f27 LC |
229 | return err->msg; |
230 | } | |
231 | ||
2ee2f1e4 MA |
232 | void error_report_err(Error *err) |
233 | { | |
234 | error_report("%s", error_get_pretty(err)); | |
50b7b000 | 235 | if (err->hint) { |
4c8b7c8b | 236 | error_printf("%s", err->hint->str); |
50b7b000 | 237 | } |
2ee2f1e4 MA |
238 | error_free(err); |
239 | } | |
240 | ||
e43ead1d AF |
241 | void warn_report_err(Error *err) |
242 | { | |
243 | warn_report("%s", error_get_pretty(err)); | |
244 | if (err->hint) { | |
4c8b7c8b | 245 | error_printf("%s", err->hint->str); |
e43ead1d AF |
246 | } |
247 | error_free(err); | |
248 | } | |
249 | ||
8277d2aa MA |
250 | void error_reportf_err(Error *err, const char *fmt, ...) |
251 | { | |
252 | va_list ap; | |
253 | ||
254 | va_start(ap, fmt); | |
255 | error_vprepend(&err, fmt, ap); | |
256 | va_end(ap); | |
257 | error_report_err(err); | |
258 | } | |
259 | ||
e43ead1d AF |
260 | |
261 | void warn_reportf_err(Error *err, const char *fmt, ...) | |
262 | { | |
263 | va_list ap; | |
264 | ||
265 | va_start(ap, fmt); | |
266 | error_vprepend(&err, fmt, ap); | |
267 | va_end(ap); | |
268 | warn_report_err(err); | |
269 | } | |
270 | ||
d5ec4f27 LC |
271 | void error_free(Error *err) |
272 | { | |
273 | if (err) { | |
7267c094 | 274 | g_free(err->msg); |
50b7b000 EB |
275 | if (err->hint) { |
276 | g_string_free(err->hint, true); | |
277 | } | |
7267c094 | 278 | g_free(err); |
d5ec4f27 LC |
279 | } |
280 | } | |
281 | ||
a12a5a1a EB |
282 | void error_free_or_abort(Error **errp) |
283 | { | |
284 | assert(errp && *errp); | |
285 | error_free(*errp); | |
286 | *errp = NULL; | |
287 | } | |
288 | ||
64dfefed | 289 | void error_propagate(Error **dst_errp, Error *local_err) |
d5ec4f27 | 290 | { |
a29a37b9 MA |
291 | if (!local_err) { |
292 | return; | |
293 | } | |
3ffef1a5 | 294 | error_handle(dst_errp, local_err); |
d5ec4f27 | 295 | } |
4b576648 MA |
296 | |
297 | void error_propagate_prepend(Error **dst_errp, Error *err, | |
298 | const char *fmt, ...) | |
299 | { | |
300 | va_list ap; | |
301 | ||
302 | if (dst_errp && !*dst_errp) { | |
303 | va_start(ap, fmt); | |
304 | error_vprepend(&err, fmt, ap); | |
305 | va_end(ap); | |
306 | } /* else error is being ignored, don't bother with prepending */ | |
307 | error_propagate(dst_errp, err); | |
308 | } |