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