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