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