xref: /openbmc/qemu/util/error.c (revision c11b0583)
1 /*
2  * QEMU Error Objects
3  *
4  * Copyright IBM, Corp. 2011
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.  See
10  * the COPYING.LIB file in the top-level directory.
11  */
12 
13 #include "qemu-common.h"
14 #include "qapi/error.h"
15 #include "qemu/error-report.h"
16 
17 struct Error
18 {
19     char *msg;
20     ErrorClass err_class;
21     const char *src, *func;
22     int line;
23 };
24 
25 Error *error_abort;
26 
27 static void error_do_abort(Error *err)
28 {
29     fprintf(stderr, "Unexpected error in %s() at %s:%d:\n",
30             err->func, err->src, err->line);
31     error_report_err(err);
32     abort();
33 }
34 
35 static void error_setv(Error **errp,
36                        const char *src, int line, const char *func,
37                        ErrorClass err_class, const char *fmt, va_list ap)
38 {
39     Error *err;
40     int saved_errno = errno;
41 
42     if (errp == NULL) {
43         return;
44     }
45     assert(*errp == NULL);
46 
47     err = g_malloc0(sizeof(*err));
48     err->msg = g_strdup_vprintf(fmt, ap);
49     err->err_class = err_class;
50     err->src = src;
51     err->line = line;
52     err->func = func;
53 
54     if (errp == &error_abort) {
55         error_do_abort(err);
56     }
57 
58     *errp = err;
59 
60     errno = saved_errno;
61 }
62 
63 void error_set_internal(Error **errp,
64                         const char *src, int line, const char *func,
65                         ErrorClass err_class, const char *fmt, ...)
66 {
67     va_list ap;
68 
69     va_start(ap, fmt);
70     error_setv(errp, src, line, func, err_class, fmt, ap);
71     va_end(ap);
72 }
73 
74 void error_setg_internal(Error **errp,
75                          const char *src, int line, const char *func,
76                          const char *fmt, ...)
77 {
78     va_list ap;
79 
80     va_start(ap, fmt);
81     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap);
82     va_end(ap);
83 }
84 
85 void error_setg_errno_internal(Error **errp,
86                                const char *src, int line, const char *func,
87                                int os_errno, const char *fmt, ...)
88 {
89     va_list ap;
90     char *msg;
91     int saved_errno = errno;
92 
93     if (errp == NULL) {
94         return;
95     }
96 
97     va_start(ap, fmt);
98     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap);
99     va_end(ap);
100 
101     if (os_errno != 0) {
102         msg = (*errp)->msg;
103         (*errp)->msg = g_strdup_printf("%s: %s", msg, strerror(os_errno));
104         g_free(msg);
105     }
106 
107     errno = saved_errno;
108 }
109 
110 void error_setg_file_open_internal(Error **errp,
111                                    const char *src, int line, const char *func,
112                                    int os_errno, const char *filename)
113 {
114     error_setg_errno_internal(errp, src, line, func, os_errno,
115                               "Could not open '%s'", filename);
116 }
117 
118 #ifdef _WIN32
119 
120 void error_setg_win32_internal(Error **errp,
121                                const char *src, int line, const char *func,
122                                int win32_err, const char *fmt, ...)
123 {
124     va_list ap;
125     char *msg1, *msg2;
126 
127     if (errp == NULL) {
128         return;
129     }
130 
131     va_start(ap, fmt);
132     error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap);
133     va_end(ap);
134 
135     if (win32_err != 0) {
136         msg1 = (*errp)->msg;
137         msg2 = g_win32_error_message(win32_err);
138         (*errp)->msg = g_strdup_printf("%s: %s (error: %x)", msg1, msg2,
139                                        (unsigned)win32_err);
140         g_free(msg2);
141         g_free(msg1);
142     }
143 }
144 
145 #endif
146 
147 Error *error_copy(const Error *err)
148 {
149     Error *err_new;
150 
151     err_new = g_malloc0(sizeof(*err));
152     err_new->msg = g_strdup(err->msg);
153     err_new->err_class = err->err_class;
154 
155     return err_new;
156 }
157 
158 ErrorClass error_get_class(const Error *err)
159 {
160     return err->err_class;
161 }
162 
163 const char *error_get_pretty(Error *err)
164 {
165     return err->msg;
166 }
167 
168 void error_report_err(Error *err)
169 {
170     error_report("%s", error_get_pretty(err));
171     error_free(err);
172 }
173 
174 void error_free(Error *err)
175 {
176     if (err) {
177         g_free(err->msg);
178         g_free(err);
179     }
180 }
181 
182 void error_propagate(Error **dst_errp, Error *local_err)
183 {
184     if (local_err && dst_errp == &error_abort) {
185         error_do_abort(local_err);
186     } else if (dst_errp && !*dst_errp) {
187         *dst_errp = local_err;
188     } else if (local_err) {
189         error_free(local_err);
190     }
191 }
192