]>
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 SW |
14 | |
15 | #include "qemu-common.h" | |
7b1b5d19 | 16 | #include "qapi/error.h" |
073a3411 | 17 | #include "qemu/error-report.h" |
d5ec4f27 LC |
18 | |
19 | struct Error | |
20 | { | |
d5ec4f27 | 21 | char *msg; |
13f59ae8 | 22 | ErrorClass err_class; |
1e9b65bb MA |
23 | const char *src, *func; |
24 | int line; | |
50b7b000 | 25 | GString *hint; |
d5ec4f27 LC |
26 | }; |
27 | ||
5d24ee70 | 28 | Error *error_abort; |
a29a37b9 | 29 | Error *error_fatal; |
5d24ee70 | 30 | |
a29a37b9 | 31 | static void error_handle_fatal(Error **errp, Error *err) |
1e9b65bb | 32 | { |
a29a37b9 MA |
33 | if (errp == &error_abort) { |
34 | fprintf(stderr, "Unexpected error in %s() at %s:%d:\n", | |
35 | err->func, err->src, err->line); | |
36 | error_report_err(err); | |
37 | abort(); | |
38 | } | |
39 | if (errp == &error_fatal) { | |
40 | error_report_err(err); | |
41 | exit(1); | |
42 | } | |
1e9b65bb MA |
43 | } |
44 | ||
45 | static void error_setv(Error **errp, | |
46 | const char *src, int line, const char *func, | |
47 | ErrorClass err_class, const char *fmt, va_list ap) | |
d5ec4f27 LC |
48 | { |
49 | Error *err; | |
b276d249 | 50 | int saved_errno = errno; |
d5ec4f27 LC |
51 | |
52 | if (errp == NULL) { | |
53 | return; | |
54 | } | |
d195325b | 55 | assert(*errp == NULL); |
d5ec4f27 | 56 | |
7267c094 | 57 | err = g_malloc0(sizeof(*err)); |
df1e608a | 58 | err->msg = g_strdup_vprintf(fmt, ap); |
13f59ae8 | 59 | err->err_class = err_class; |
1e9b65bb MA |
60 | err->src = src; |
61 | err->line = line; | |
62 | err->func = func; | |
d5ec4f27 | 63 | |
a29a37b9 | 64 | error_handle_fatal(errp, err); |
d5ec4f27 | 65 | *errp = err; |
b276d249 HR |
66 | |
67 | errno = saved_errno; | |
d5ec4f27 LC |
68 | } |
69 | ||
1e9b65bb MA |
70 | void error_set_internal(Error **errp, |
71 | const char *src, int line, const char *func, | |
72 | ErrorClass err_class, const char *fmt, ...) | |
55237508 MA |
73 | { |
74 | va_list ap; | |
75 | ||
76 | va_start(ap, fmt); | |
1e9b65bb | 77 | error_setv(errp, src, line, func, err_class, fmt, ap); |
55237508 MA |
78 | va_end(ap); |
79 | } | |
80 | ||
1e9b65bb MA |
81 | void error_setg_internal(Error **errp, |
82 | const char *src, int line, const char *func, | |
83 | const char *fmt, ...) | |
a9499ddd MA |
84 | { |
85 | va_list ap; | |
86 | ||
87 | va_start(ap, fmt); | |
1e9b65bb | 88 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap); |
a9499ddd MA |
89 | va_end(ap); |
90 | } | |
91 | ||
1e9b65bb MA |
92 | void error_setg_errno_internal(Error **errp, |
93 | const char *src, int line, const char *func, | |
94 | int os_errno, const char *fmt, ...) | |
680d16dc | 95 | { |
680d16dc | 96 | va_list ap; |
55237508 | 97 | char *msg; |
b276d249 | 98 | int saved_errno = errno; |
680d16dc PB |
99 | |
100 | if (errp == NULL) { | |
101 | return; | |
102 | } | |
680d16dc PB |
103 | |
104 | va_start(ap, fmt); | |
1e9b65bb | 105 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap); |
680d16dc | 106 | va_end(ap); |
680d16dc | 107 | |
55237508 MA |
108 | if (os_errno != 0) { |
109 | msg = (*errp)->msg; | |
110 | (*errp)->msg = g_strdup_printf("%s: %s", msg, strerror(os_errno)); | |
111 | g_free(msg); | |
5d24ee70 PC |
112 | } |
113 | ||
b276d249 | 114 | errno = saved_errno; |
680d16dc PB |
115 | } |
116 | ||
1e9b65bb MA |
117 | void error_setg_file_open_internal(Error **errp, |
118 | const char *src, int line, const char *func, | |
119 | int os_errno, const char *filename) | |
54028d75 | 120 | { |
1e9b65bb MA |
121 | error_setg_errno_internal(errp, src, line, func, os_errno, |
122 | "Could not open '%s'", filename); | |
54028d75 LC |
123 | } |
124 | ||
50b7b000 EB |
125 | void error_append_hint(Error **errp, const char *fmt, ...) |
126 | { | |
127 | va_list ap; | |
128 | int saved_errno = errno; | |
129 | Error *err; | |
130 | ||
131 | if (!errp) { | |
132 | return; | |
133 | } | |
134 | err = *errp; | |
135 | assert(err && errp != &error_abort); | |
136 | ||
137 | if (!err->hint) { | |
138 | err->hint = g_string_new(NULL); | |
139 | } | |
140 | va_start(ap, fmt); | |
141 | g_string_append_vprintf(err->hint, fmt, ap); | |
142 | va_end(ap); | |
143 | ||
144 | errno = saved_errno; | |
145 | } | |
146 | ||
20840d4c TS |
147 | #ifdef _WIN32 |
148 | ||
1e9b65bb MA |
149 | void error_setg_win32_internal(Error **errp, |
150 | const char *src, int line, const char *func, | |
151 | int win32_err, const char *fmt, ...) | |
20840d4c | 152 | { |
20840d4c | 153 | va_list ap; |
55237508 | 154 | char *msg1, *msg2; |
20840d4c TS |
155 | |
156 | if (errp == NULL) { | |
157 | return; | |
158 | } | |
20840d4c TS |
159 | |
160 | va_start(ap, fmt); | |
1e9b65bb | 161 | error_setv(errp, src, line, func, ERROR_CLASS_GENERIC_ERROR, fmt, ap); |
55237508 MA |
162 | va_end(ap); |
163 | ||
20840d4c | 164 | if (win32_err != 0) { |
55237508 MA |
165 | msg1 = (*errp)->msg; |
166 | msg2 = g_win32_error_message(win32_err); | |
167 | (*errp)->msg = g_strdup_printf("%s: %s (error: %x)", msg1, msg2, | |
168 | (unsigned)win32_err); | |
20840d4c TS |
169 | g_free(msg2); |
170 | g_free(msg1); | |
5d24ee70 | 171 | } |
20840d4c TS |
172 | } |
173 | ||
174 | #endif | |
175 | ||
79020cfc LC |
176 | Error *error_copy(const Error *err) |
177 | { | |
178 | Error *err_new; | |
179 | ||
180 | err_new = g_malloc0(sizeof(*err)); | |
181 | err_new->msg = g_strdup(err->msg); | |
13f59ae8 | 182 | err_new->err_class = err->err_class; |
88e2ce29 EB |
183 | err_new->src = err->src; |
184 | err_new->line = err->line; | |
185 | err_new->func = err->func; | |
50b7b000 EB |
186 | if (err->hint) { |
187 | err_new->hint = g_string_new(err->hint->str); | |
188 | } | |
79020cfc LC |
189 | |
190 | return err_new; | |
191 | } | |
192 | ||
ea25fbca LC |
193 | ErrorClass error_get_class(const Error *err) |
194 | { | |
195 | return err->err_class; | |
196 | } | |
197 | ||
d5ec4f27 LC |
198 | const char *error_get_pretty(Error *err) |
199 | { | |
d5ec4f27 LC |
200 | return err->msg; |
201 | } | |
202 | ||
2ee2f1e4 MA |
203 | void error_report_err(Error *err) |
204 | { | |
205 | error_report("%s", error_get_pretty(err)); | |
50b7b000 EB |
206 | if (err->hint) { |
207 | error_printf_unless_qmp("%s\n", err->hint->str); | |
208 | } | |
2ee2f1e4 MA |
209 | error_free(err); |
210 | } | |
211 | ||
d5ec4f27 LC |
212 | void error_free(Error *err) |
213 | { | |
214 | if (err) { | |
7267c094 | 215 | g_free(err->msg); |
50b7b000 EB |
216 | if (err->hint) { |
217 | g_string_free(err->hint, true); | |
218 | } | |
7267c094 | 219 | g_free(err); |
d5ec4f27 LC |
220 | } |
221 | } | |
222 | ||
64dfefed | 223 | void error_propagate(Error **dst_errp, Error *local_err) |
d5ec4f27 | 224 | { |
a29a37b9 MA |
225 | if (!local_err) { |
226 | return; | |
227 | } | |
228 | error_handle_fatal(dst_errp, local_err); | |
229 | if (dst_errp && !*dst_errp) { | |
64dfefed | 230 | *dst_errp = local_err; |
a29a37b9 | 231 | } else { |
d5ec4f27 LC |
232 | error_free(local_err); |
233 | } | |
234 | } |