]>
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); | |
137 | (*errp)->msg = g_string_free(newmsg, 0); | |
138 | } | |
139 | ||
140 | void error_prepend(Error **errp, const char *fmt, ...) | |
141 | { | |
142 | va_list ap; | |
143 | ||
144 | va_start(ap, fmt); | |
145 | error_vprepend(errp, fmt, ap); | |
146 | va_end(ap); | |
147 | } | |
148 | ||
50b7b000 EB |
149 | void error_append_hint(Error **errp, const char *fmt, ...) |
150 | { | |
151 | va_list ap; | |
152 | int saved_errno = errno; | |
153 | Error *err; | |
154 | ||
155 | if (!errp) { | |
156 | return; | |
157 | } | |
158 | err = *errp; | |
f4d0064a | 159 | assert(err && errp != &error_abort && errp != &error_fatal); |
50b7b000 EB |
160 | |
161 | if (!err->hint) { | |
162 | err->hint = g_string_new(NULL); | |
163 | } | |
164 | va_start(ap, fmt); | |
165 | g_string_append_vprintf(err->hint, fmt, ap); | |
166 | va_end(ap); | |
167 | ||
168 | errno = saved_errno; | |
169 | } | |
170 | ||
20840d4c TS |
171 | #ifdef _WIN32 |
172 | ||
1e9b65bb MA |
173 | void error_setg_win32_internal(Error **errp, |
174 | const char *src, int line, const char *func, | |
175 | int win32_err, const char *fmt, ...) | |
20840d4c | 176 | { |
20840d4c | 177 | va_list ap; |
20e2dec1 | 178 | char *suffix = NULL; |
20840d4c TS |
179 | |
180 | if (errp == NULL) { | |
181 | return; | |
182 | } | |
20840d4c | 183 | |
20e2dec1 DB |
184 | if (win32_err != 0) { |
185 | suffix = g_win32_error_message(win32_err); | |
186 | } | |
187 | ||
20840d4c | 188 | va_start(ap, fmt); |
20e2dec1 DB |
189 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, |
190 | fmt, ap, suffix); | |
55237508 MA |
191 | va_end(ap); |
192 | ||
20e2dec1 | 193 | g_free(suffix); |
20840d4c TS |
194 | } |
195 | ||
196 | #endif | |
197 | ||
79020cfc LC |
198 | Error *error_copy(const Error *err) |
199 | { | |
200 | Error *err_new; | |
201 | ||
202 | err_new = g_malloc0(sizeof(*err)); | |
203 | err_new->msg = g_strdup(err->msg); | |
13f59ae8 | 204 | err_new->err_class = err->err_class; |
88e2ce29 EB |
205 | err_new->src = err->src; |
206 | err_new->line = err->line; | |
207 | err_new->func = err->func; | |
50b7b000 EB |
208 | if (err->hint) { |
209 | err_new->hint = g_string_new(err->hint->str); | |
210 | } | |
79020cfc LC |
211 | |
212 | return err_new; | |
213 | } | |
214 | ||
ea25fbca LC |
215 | ErrorClass error_get_class(const Error *err) |
216 | { | |
217 | return err->err_class; | |
218 | } | |
219 | ||
d59ce6f3 | 220 | const char *error_get_pretty(const Error *err) |
d5ec4f27 | 221 | { |
d5ec4f27 LC |
222 | return err->msg; |
223 | } | |
224 | ||
2ee2f1e4 MA |
225 | void error_report_err(Error *err) |
226 | { | |
227 | error_report("%s", error_get_pretty(err)); | |
50b7b000 | 228 | if (err->hint) { |
543202c0 | 229 | error_printf_unless_qmp("%s", err->hint->str); |
50b7b000 | 230 | } |
2ee2f1e4 MA |
231 | error_free(err); |
232 | } | |
233 | ||
8277d2aa MA |
234 | void error_reportf_err(Error *err, const char *fmt, ...) |
235 | { | |
236 | va_list ap; | |
237 | ||
238 | va_start(ap, fmt); | |
239 | error_vprepend(&err, fmt, ap); | |
240 | va_end(ap); | |
241 | error_report_err(err); | |
242 | } | |
243 | ||
d5ec4f27 LC |
244 | void error_free(Error *err) |
245 | { | |
246 | if (err) { | |
7267c094 | 247 | g_free(err->msg); |
50b7b000 EB |
248 | if (err->hint) { |
249 | g_string_free(err->hint, true); | |
250 | } | |
7267c094 | 251 | g_free(err); |
d5ec4f27 LC |
252 | } |
253 | } | |
254 | ||
a12a5a1a EB |
255 | void error_free_or_abort(Error **errp) |
256 | { | |
257 | assert(errp && *errp); | |
258 | error_free(*errp); | |
259 | *errp = NULL; | |
260 | } | |
261 | ||
64dfefed | 262 | void error_propagate(Error **dst_errp, Error *local_err) |
d5ec4f27 | 263 | { |
a29a37b9 MA |
264 | if (!local_err) { |
265 | return; | |
266 | } | |
267 | error_handle_fatal(dst_errp, local_err); | |
268 | if (dst_errp && !*dst_errp) { | |
64dfefed | 269 | *dst_errp = local_err; |
a29a37b9 | 270 | } else { |
d5ec4f27 LC |
271 | error_free(local_err); |
272 | } | |
273 | } |