xref: /openbmc/qemu/util/error.c (revision f665537f1543050cb9e756d4affff10cdf92b7ed)
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 }
315