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