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