]>
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" |
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 PB |
105 | |
106 | if (errp == NULL) { | |
107 | return; | |
108 | } | |
680d16dc PB |
109 | |
110 | va_start(ap, fmt); | |
20e2dec1 DB |
111 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap, |
112 | os_errno != 0 ? strerror(os_errno) : NULL); | |
680d16dc | 113 | va_end(ap); |
680d16dc | 114 | |
b276d249 | 115 | errno = saved_errno; |
680d16dc PB |
116 | } |
117 | ||
1e9b65bb MA |
118 | void error_setg_file_open_internal(Error **errp, |
119 | const char *src, int line, const char *func, | |
120 | int os_errno, const char *filename) | |
54028d75 | 121 | { |
1e9b65bb MA |
122 | error_setg_errno_internal(errp, src, line, func, os_errno, |
123 | "Could not open '%s'", filename); | |
54028d75 LC |
124 | } |
125 | ||
8277d2aa MA |
126 | void error_vprepend(Error **errp, const char *fmt, va_list ap) |
127 | { | |
128 | GString *newmsg; | |
129 | ||
130 | if (!errp) { | |
131 | return; | |
132 | } | |
133 | ||
134 | newmsg = g_string_new(NULL); | |
135 | g_string_vprintf(newmsg, fmt, ap); | |
136 | g_string_append(newmsg, (*errp)->msg); | |
536eeea8 | 137 | g_free((*errp)->msg); |
8277d2aa MA |
138 | (*errp)->msg = g_string_free(newmsg, 0); |
139 | } | |
140 | ||
141 | void error_prepend(Error **errp, const char *fmt, ...) | |
142 | { | |
143 | va_list ap; | |
144 | ||
145 | va_start(ap, fmt); | |
146 | error_vprepend(errp, fmt, ap); | |
147 | va_end(ap); | |
148 | } | |
149 | ||
50b7b000 EB |
150 | void error_append_hint(Error **errp, const char *fmt, ...) |
151 | { | |
152 | va_list ap; | |
153 | int saved_errno = errno; | |
154 | Error *err; | |
155 | ||
156 | if (!errp) { | |
157 | return; | |
158 | } | |
159 | err = *errp; | |
f4d0064a | 160 | assert(err && errp != &error_abort && errp != &error_fatal); |
50b7b000 EB |
161 | |
162 | if (!err->hint) { | |
163 | err->hint = g_string_new(NULL); | |
164 | } | |
165 | va_start(ap, fmt); | |
166 | g_string_append_vprintf(err->hint, fmt, ap); | |
167 | va_end(ap); | |
168 | ||
169 | errno = saved_errno; | |
170 | } | |
171 | ||
20840d4c TS |
172 | #ifdef _WIN32 |
173 | ||
1e9b65bb MA |
174 | void error_setg_win32_internal(Error **errp, |
175 | const char *src, int line, const char *func, | |
176 | int win32_err, const char *fmt, ...) | |
20840d4c | 177 | { |
20840d4c | 178 | va_list ap; |
20e2dec1 | 179 | char *suffix = NULL; |
20840d4c TS |
180 | |
181 | if (errp == NULL) { | |
182 | return; | |
183 | } | |
20840d4c | 184 | |
20e2dec1 DB |
185 | if (win32_err != 0) { |
186 | suffix = g_win32_error_message(win32_err); | |
187 | } | |
188 | ||
20840d4c | 189 | va_start(ap, fmt); |
20e2dec1 DB |
190 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, |
191 | fmt, ap, suffix); | |
55237508 MA |
192 | va_end(ap); |
193 | ||
20e2dec1 | 194 | g_free(suffix); |
20840d4c TS |
195 | } |
196 | ||
197 | #endif | |
198 | ||
79020cfc LC |
199 | Error *error_copy(const Error *err) |
200 | { | |
201 | Error *err_new; | |
202 | ||
203 | err_new = g_malloc0(sizeof(*err)); | |
204 | err_new->msg = g_strdup(err->msg); | |
13f59ae8 | 205 | err_new->err_class = err->err_class; |
88e2ce29 EB |
206 | err_new->src = err->src; |
207 | err_new->line = err->line; | |
208 | err_new->func = err->func; | |
50b7b000 EB |
209 | if (err->hint) { |
210 | err_new->hint = g_string_new(err->hint->str); | |
211 | } | |
79020cfc LC |
212 | |
213 | return err_new; | |
214 | } | |
215 | ||
ea25fbca LC |
216 | ErrorClass error_get_class(const Error *err) |
217 | { | |
218 | return err->err_class; | |
219 | } | |
220 | ||
d59ce6f3 | 221 | const char *error_get_pretty(const Error *err) |
d5ec4f27 | 222 | { |
d5ec4f27 LC |
223 | return err->msg; |
224 | } | |
225 | ||
2ee2f1e4 MA |
226 | void error_report_err(Error *err) |
227 | { | |
228 | error_report("%s", error_get_pretty(err)); | |
50b7b000 | 229 | if (err->hint) { |
543202c0 | 230 | error_printf_unless_qmp("%s", err->hint->str); |
50b7b000 | 231 | } |
2ee2f1e4 MA |
232 | error_free(err); |
233 | } | |
234 | ||
e43ead1d AF |
235 | void warn_report_err(Error *err) |
236 | { | |
237 | warn_report("%s", error_get_pretty(err)); | |
238 | if (err->hint) { | |
239 | error_printf_unless_qmp("%s", err->hint->str); | |
240 | } | |
241 | error_free(err); | |
242 | } | |
243 | ||
8277d2aa MA |
244 | void error_reportf_err(Error *err, const char *fmt, ...) |
245 | { | |
246 | va_list ap; | |
247 | ||
248 | va_start(ap, fmt); | |
249 | error_vprepend(&err, fmt, ap); | |
250 | va_end(ap); | |
251 | error_report_err(err); | |
252 | } | |
253 | ||
e43ead1d AF |
254 | |
255 | void warn_reportf_err(Error *err, const char *fmt, ...) | |
256 | { | |
257 | va_list ap; | |
258 | ||
259 | va_start(ap, fmt); | |
260 | error_vprepend(&err, fmt, ap); | |
261 | va_end(ap); | |
262 | warn_report_err(err); | |
263 | } | |
264 | ||
d5ec4f27 LC |
265 | void error_free(Error *err) |
266 | { | |
267 | if (err) { | |
7267c094 | 268 | g_free(err->msg); |
50b7b000 EB |
269 | if (err->hint) { |
270 | g_string_free(err->hint, true); | |
271 | } | |
7267c094 | 272 | g_free(err); |
d5ec4f27 LC |
273 | } |
274 | } | |
275 | ||
a12a5a1a EB |
276 | void error_free_or_abort(Error **errp) |
277 | { | |
278 | assert(errp && *errp); | |
279 | error_free(*errp); | |
280 | *errp = NULL; | |
281 | } | |
282 | ||
64dfefed | 283 | void error_propagate(Error **dst_errp, Error *local_err) |
d5ec4f27 | 284 | { |
a29a37b9 MA |
285 | if (!local_err) { |
286 | return; | |
287 | } | |
288 | error_handle_fatal(dst_errp, local_err); | |
289 | if (dst_errp && !*dst_errp) { | |
64dfefed | 290 | *dst_errp = local_err; |
a29a37b9 | 291 | } else { |
d5ec4f27 LC |
292 | error_free(local_err); |
293 | } | |
294 | } |