1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14#include "monitor/monitor.h"
15#include "qemu/error-report.h"
16
17
18
19
20
21typedef enum {
22 REPORT_TYPE_ERROR,
23 REPORT_TYPE_WARNING,
24 REPORT_TYPE_INFO,
25} report_type;
26
27
28bool message_with_timestamp;
29bool error_with_guestname;
30const char *error_guest_name;
31
32int error_printf(const char *fmt, ...)
33{
34 va_list ap;
35 int ret;
36
37 va_start(ap, fmt);
38 ret = error_vprintf(fmt, ap);
39 va_end(ap);
40 return ret;
41}
42
43static Location std_loc = {
44 .kind = LOC_NONE
45};
46static Location *cur_loc = &std_loc;
47
48
49
50
51
52
53Location *loc_push_restore(Location *loc)
54{
55 assert(!loc->prev);
56 loc->prev = cur_loc;
57 cur_loc = loc;
58 return loc;
59}
60
61
62
63
64
65
66
67Location *loc_push_none(Location *loc)
68{
69 loc->kind = LOC_NONE;
70 loc->prev = NULL;
71 return loc_push_restore(loc);
72}
73
74
75
76
77
78Location *loc_pop(Location *loc)
79{
80 assert(cur_loc == loc && loc->prev);
81 cur_loc = loc->prev;
82 loc->prev = NULL;
83 return loc;
84}
85
86
87
88
89Location *loc_save(Location *loc)
90{
91 *loc = *cur_loc;
92 loc->prev = NULL;
93 return loc;
94}
95
96
97
98
99void loc_restore(Location *loc)
100{
101 Location *prev = cur_loc->prev;
102 assert(!loc->prev);
103 *cur_loc = *loc;
104 cur_loc->prev = prev;
105}
106
107
108
109
110void loc_set_none(void)
111{
112 cur_loc->kind = LOC_NONE;
113}
114
115
116
117
118void loc_set_cmdline(char **argv, int idx, int cnt)
119{
120 cur_loc->kind = LOC_CMDLINE;
121 cur_loc->num = cnt;
122 cur_loc->ptr = argv + idx;
123}
124
125
126
127
128void loc_set_file(const char *fname, int lno)
129{
130 assert (fname || cur_loc->kind == LOC_FILE);
131 cur_loc->kind = LOC_FILE;
132 cur_loc->num = lno;
133 if (fname) {
134 cur_loc->ptr = fname;
135 }
136}
137
138
139
140
141static void print_loc(void)
142{
143 const char *sep = "";
144 int i;
145 const char *const *argp;
146
147 if (!monitor_cur() && g_get_prgname()) {
148 error_printf("%s:", g_get_prgname());
149 sep = " ";
150 }
151 switch (cur_loc->kind) {
152 case LOC_CMDLINE:
153 argp = cur_loc->ptr;
154 for (i = 0; i < cur_loc->num; i++) {
155 error_printf("%s%s", sep, argp[i]);
156 sep = " ";
157 }
158 error_printf(": ");
159 break;
160 case LOC_FILE:
161 error_printf("%s:", (const char *)cur_loc->ptr);
162 if (cur_loc->num) {
163 error_printf("%d:", cur_loc->num);
164 }
165 error_printf(" ");
166 break;
167 default:
168 error_printf("%s", sep);
169 }
170}
171
172static char *
173real_time_iso8601(void)
174{
175#if GLIB_CHECK_VERSION(2,62,0)
176 g_autoptr(GDateTime) dt = g_date_time_new_now_utc();
177
178#pragma GCC diagnostic push
179#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
180 return g_date_time_format_iso8601(dt);
181#pragma GCC diagnostic pop
182#else
183 GTimeVal tv;
184 g_get_current_time(&tv);
185 return g_time_val_to_iso8601(&tv);
186#endif
187}
188
189
190
191
192
193
194
195
196G_GNUC_PRINTF(2, 0)
197static void vreport(report_type type, const char *fmt, va_list ap)
198{
199 gchar *timestr;
200
201 if (message_with_timestamp && !monitor_cur()) {
202 timestr = real_time_iso8601();
203 error_printf("%s ", timestr);
204 g_free(timestr);
205 }
206
207
208 if (error_with_guestname && error_guest_name && !monitor_cur()) {
209 error_printf("%s ", error_guest_name);
210 }
211
212 print_loc();
213
214 switch (type) {
215 case REPORT_TYPE_ERROR:
216 break;
217 case REPORT_TYPE_WARNING:
218 error_printf("warning: ");
219 break;
220 case REPORT_TYPE_INFO:
221 error_printf("info: ");
222 break;
223 }
224
225 error_vprintf(fmt, ap);
226 error_printf("\n");
227}
228
229
230
231
232
233
234
235
236void error_vreport(const char *fmt, va_list ap)
237{
238 vreport(REPORT_TYPE_ERROR, fmt, ap);
239}
240
241
242
243
244
245
246
247void warn_vreport(const char *fmt, va_list ap)
248{
249 vreport(REPORT_TYPE_WARNING, fmt, ap);
250}
251
252
253
254
255
256
257
258
259void info_vreport(const char *fmt, va_list ap)
260{
261 vreport(REPORT_TYPE_INFO, fmt, ap);
262}
263
264
265
266
267
268
269
270
271void error_report(const char *fmt, ...)
272{
273 va_list ap;
274
275 va_start(ap, fmt);
276 vreport(REPORT_TYPE_ERROR, fmt, ap);
277 va_end(ap);
278}
279
280
281
282
283
284
285
286void warn_report(const char *fmt, ...)
287{
288 va_list ap;
289
290 va_start(ap, fmt);
291 vreport(REPORT_TYPE_WARNING, fmt, ap);
292 va_end(ap);
293}
294
295
296
297
298
299
300
301
302void info_report(const char *fmt, ...)
303{
304 va_list ap;
305
306 va_start(ap, fmt);
307 vreport(REPORT_TYPE_INFO, fmt, ap);
308 va_end(ap);
309}
310
311
312
313
314
315
316bool error_report_once_cond(bool *printed, const char *fmt, ...)
317{
318 va_list ap;
319
320 assert(printed);
321 if (*printed) {
322 return false;
323 }
324 *printed = true;
325 va_start(ap, fmt);
326 vreport(REPORT_TYPE_ERROR, fmt, ap);
327 va_end(ap);
328 return true;
329}
330
331
332
333
334
335
336bool warn_report_once_cond(bool *printed, const char *fmt, ...)
337{
338 va_list ap;
339
340 assert(printed);
341 if (*printed) {
342 return false;
343 }
344 *printed = true;
345 va_start(ap, fmt);
346 vreport(REPORT_TYPE_WARNING, fmt, ap);
347 va_end(ap);
348 return true;
349}
350
351static char *qemu_glog_domains;
352
353static void qemu_log_func(const gchar *log_domain,
354 GLogLevelFlags log_level,
355 const gchar *message,
356 gpointer user_data)
357{
358 switch (log_level & G_LOG_LEVEL_MASK) {
359 case G_LOG_LEVEL_DEBUG:
360 case G_LOG_LEVEL_INFO:
361
362
363
364
365 if (qemu_glog_domains == NULL) {
366 break;
367 }
368 if (strcmp(qemu_glog_domains, "all") != 0 &&
369 (log_domain == NULL || !strstr(qemu_glog_domains, log_domain))) {
370 break;
371 }
372
373 case G_LOG_LEVEL_MESSAGE:
374 info_report("%s%s%s",
375 log_domain ?: "", log_domain ? ": " : "", message);
376
377 break;
378 case G_LOG_LEVEL_WARNING:
379 warn_report("%s%s%s",
380 log_domain ?: "", log_domain ? ": " : "", message);
381 break;
382 case G_LOG_LEVEL_CRITICAL:
383 case G_LOG_LEVEL_ERROR:
384 error_report("%s%s%s",
385 log_domain ?: "", log_domain ? ": " : "", message);
386 break;
387 }
388}
389
390void error_init(const char *argv0)
391{
392 const char *p = strrchr(argv0, '/');
393
394
395 g_set_prgname(p ? p + 1 : argv0);
396
397
398
399
400
401 g_log_set_default_handler(qemu_log_func, NULL);
402 g_warn_if_fail(qemu_glog_domains == NULL);
403 qemu_glog_domains = g_strdup(g_getenv("G_MESSAGES_DEBUG"));
404}
405