00001 #include "er_errors.h" 00002 00003 #include "ac_app_context.h" 00004 #include "application_config.h" 00005 00006 #include "common/utilities.h" 00007 00008 #include <glib/gprintf.h> 00009 00010 void er_fatal_quiet() 00011 { 00012 EXIT_APPLICATION; 00013 } 00014 00015 void er_fatal() 00016 { 00017 er_fatal_general; 00018 } 00019 00020 void er_fatal_msg(const char* msg) 00021 { 00022 er_show_error_msg(msg); 00023 EXIT_APPLICATION; 00024 } 00025 00026 void er_show_error_msg(const char* msg) 00027 { 00028 WHEN_SYMBIAN(ex_show_error_msg(msg)); 00029 UNLESS_SYMBIAN(logt(msg)); 00030 } 00031 00032 /* 00033 !concept {:name => "Flexible error reporting"} 00034 */ 00035 00036 static 00037 void er_log_base(int opt, void* errObj, 00038 const char* func, const char* file, int line, 00039 const char* user_msg) 00040 { 00041 char* err_msg = NULL; // just "error" if errObj not given 00042 gboolean is_dynamic_err_msg = FALSE; 00043 char* log_msg = NULL; 00044 gboolean is_dynamic_log_msg = FALSE; 00045 00046 SET_TRAP_OOM(goto nomemory); 00047 { 00048 { 00049 if (opt & er_NONE) { 00050 // Nothing to format. 00051 } else if (opt & er_POSIX) { 00052 int errCode = *(int*)errObj; 00053 err_msg = g_strdup_printf("POSIX error: %s (%d)", 00054 strerror(errCode), errCode); 00055 is_dynamic_err_msg = TRUE; 00056 } else if (opt & er_SYMBIAN) { 00057 #if defined(__SYMBIAN32__) 00058 TInt errCode = *(TInt*)errObj; 00059 err_msg = g_strdup_printf("Symbian error: %s (%d)", 00060 plat_error_strerror(errCode), errCode); 00061 is_dynamic_err_msg = TRUE; 00062 #else 00063 assert(0 && "Symbian error in non-Symbian code"); 00064 #endif /* __SYMBIAN32__ */ 00065 } else if (opt & er_GERROR) { 00066 if (G_LIKELY(errObj)) { 00067 GError* error = (GError*)errObj; 00068 err_msg = g_strdup_printf("GError: %s (%s: %d)", 00069 error->message, 00070 g_quark_to_string(error->domain), 00071 error->code); 00072 is_dynamic_err_msg = TRUE; 00073 } else { 00074 err_msg = "out of memory error"; 00075 } 00076 } else { 00077 assert(0 && "unsupported error type"); 00078 } 00079 } 00080 00081 { 00082 const char* heading = ((opt & (er_FATAL|er_OOM)) ? "FATAL" : "ERROR"); 00083 const char* inspect = (err_msg ? err_msg : "<no value>"); 00084 const char* msg = (user_msg ? user_msg : "<no message>"); 00085 log_msg = g_strdup_printf("%s: %s: %s [func %s, file %s, line %d]", 00086 heading, msg, inspect, func, file, line); 00087 is_dynamic_log_msg = TRUE; 00088 } 00089 } 00090 UNSET_TRAP_OOM(); 00091 00092 #if HAVE_TRAP_OOM 00093 ready: 00094 #endif 00095 { 00096 LogDb* logDb = ((opt & er_NODB) ? NULL : ac_global_LogDb); 00097 if (!logDb) { 00098 logt(log_msg); 00099 } else { 00100 if (!log_db_log_status_direct(logDb, NULL, log_msg)) { 00101 logt("logging failure in er_log_base"); 00102 logg("tried to log: %s", log_msg); // at least txtlog, then 00103 opt |= er_FATAL; 00104 } 00105 } 00106 00107 if (is_dynamic_err_msg) 00108 g_free(err_msg); 00109 if (is_dynamic_log_msg) 00110 g_free(log_msg); 00111 00112 if (opt & er_FREE) 00113 if (opt & er_GERROR) 00114 gx_error_free((GError*)errObj); 00115 00116 if ((opt & er_QUIET) && (opt & (er_FATAL|er_OOM))) { 00117 er_fatal_quiet(); 00118 } else if (opt & er_OOM) { 00119 er_fatal_oom; 00120 } else if (opt & er_FATAL) { 00121 #if defined(__SYMBIAN32__) 00122 if (opt & er_SYMBIAN) { 00123 TInt errCode = *(TInt*)errObj; 00124 ex_fatal_error(errCode); 00125 } else { 00126 er_fatal_general; 00127 } 00128 #else 00129 er_fatal_general; 00130 #endif /* __SYMBIAN32__ */ 00131 } 00132 } 00133 return; 00134 00135 #if HAVE_TRAP_OOM 00136 nomemory: 00137 { 00138 log_msg = "FATAL: out of memory in er_log_base"; 00139 opt |= er_OOM; 00140 goto ready; 00141 } 00142 #endif 00143 } 00144 00145 #define _er_log_impl(_errObj) \ 00146 { \ 00147 char* user_msg = NULL; \ 00148 if (user_fmt) { \ 00149 SET_TRAP_OOM_FAIL(); \ 00150 va_list argp; \ 00151 va_start(argp, user_fmt); \ 00152 g_vasprintf(&user_msg, user_fmt, argp); \ 00153 va_end(argp); \ 00154 UNSET_TRAP_OOM(); \ 00155 } \ 00156 er_log_base(opt, _errObj, func, file, line, user_msg); \ 00157 g_free(user_msg); \ 00158 return; \ 00159 WHEN_TRAP_OOM(fail: \ 00160 g_free(user_msg); \ 00161 er_log_base(er_NONE | er_OOM | opt, NULL, \ 00162 er_POSITION, \ 00163 "out of memory in _er_log_impl")); \ 00164 } 00165 00166 void _er_log_any(int opt, void* errObj, 00167 const char* func, const char* file, int line, 00168 const char* user_fmt, ...) 00169 { 00170 _er_log_impl(errObj); 00171 } 00172 00173 void _er_log_int(int opt, int errObj, 00174 const char* func, const char* file, int line, 00175 const char* user_fmt, ...) 00176 { 00177 _er_log_impl(&errObj); 00178 } 00179 00180 void _er_log_gerror(int opt, GError* errObj, 00181 const char* func, const char* file, int line, 00182 const char* user_fmt, ...) 00183 { 00184 _er_log_impl(errObj); 00185 } 00186 00187 // -------------------------------------------------- 00188 // status logging 00189 // -------------------------------------------------- 00190 00191 void er_log_status_string(const char* log_msg) 00192 { 00193 LogDb* logDb = ac_global_LogDb; 00194 if (!logDb) { 00195 logt(log_msg); 00196 } else { 00197 if (!log_db_log_status_direct(logDb, NULL, log_msg)) { 00198 logt("logging failure in er_log_status_string"); 00199 er_fatal_general; 00200 } 00201 } 00202 } 00203 00204 void er_log_status_fmt(const char* user_fmt, ...) 00205 { 00206 char* user_msg = NULL; 00207 if (user_fmt) { 00208 SET_TRAP_OOM_FAIL(); 00209 va_list argp; 00210 va_start(argp, user_fmt); 00211 g_vasprintf(&user_msg, user_fmt, argp); 00212 va_end(argp); 00213 UNSET_TRAP_OOM(); 00214 } 00215 er_log_status_string(user_msg); 00216 g_free(user_msg); 00217 return; 00218 00219 WHEN_TRAP_OOM(fail: 00220 g_free(user_msg); 00221 er_log_oom); 00222 } 00223 00224 // -------------------------------------------------- 00225 // GLib specific 00226 // -------------------------------------------------- 00227 00228 // The docs of g_error_free do not say if the error may be NULL. Well 00229 // with this function it may. 00230 void gx_error_free(GError* error) 00231 { 00232 if (error) g_error_free(error); 00233 } 00234 00235 // The "src" error may be NULL. 00236 void gx_propagate_error(GError** dest, GError* src) 00237 { 00238 if (dest) { 00239 assert((!*dest) && "dest error already set"); 00240 *dest = src; 00241 } else { 00242 gx_error_free(src); 00243 } 00244 } 00245 00246 gchar* gx_error_to_string(GError* error) 00247 { 00248 assert(error); // NULL argument not supported here 00249 GString* gs = NULL; 00250 TRAP_OOM_FAIL(gs = g_string_sized_new(128); 00251 g_string_printf(gs, "%s (%s: %d)", 00252 error->message, 00253 g_quark_to_string(error->domain), 00254 error->code)); 00255 gchar* ret = gs->str; 00256 g_string_free(gs, FALSE); 00257 return ret; 00258 #if HAVE_TRAP_OOM 00259 fail: 00260 if (gs) g_string_free(gs, TRUE); 00261 return NULL; 00262 #endif 00263 } 00264 00265 void gx_txtlog_error(GError* error) 00266 { 00267 if (error) { 00268 gchar* s = gx_error_to_string(error); 00269 if (G_LIKELY(s)) { 00270 logt(s); 00271 g_free(s); 00272 } else { 00273 logt("out of memory error"); 00274 } 00275 } else { // error == gx_error_no_memory 00276 logt("out of memory error"); 00277 } 00278 } 00279 00280 void gx_txtlog_error_free(GError* error) 00281 { 00282 gx_txtlog_error(error); 00283 if (error) g_error_free(error); 00284 } 00285 00286 void gx_txtlog_error_clear(GError** error) 00287 { 00288 if (error) { 00289 gx_txtlog_error_free(*error); 00290 *error = NULL; 00291 } 00292 } 00293 00294 gboolean gx_dblog_error_check(LogDb* logDb, GError* errorToLog, GError** error) 00295 { 00296 gchar* s = NULL; 00297 gboolean free_s = FALSE; 00298 00299 if (errorToLog) { 00300 s = gx_error_to_string(errorToLog); 00301 if (G_LIKELY(s)) { 00302 free_s = TRUE; 00303 } 00304 } 00305 if (!s) 00306 s = "out of memory error"; 00307 00308 gboolean r = log_db_log_status_direct(logDb, error, s); 00309 if (free_s) g_free(s); 00310 return r; 00311 } 00312 00313 // Takes ownership of "errorToLog" even if fails. 00314 gboolean gx_dblog_error_free_check(LogDb* logDb, GError* errorToLog, GError** error) 00315 { 00316 gboolean success = gx_dblog_error_check(logDb, errorToLog, error); 00317 gx_error_free(errorToLog); 00318 return success; 00319 } 00320 00321 // Takes ownership of "errorToLog" even if fails. 00322 gboolean gx_dblog_error_clear_check(LogDb* logDb, GError** errorToLog, GError** error) 00323 { 00324 if (!errorToLog) 00325 return TRUE; // nothing to log 00326 gboolean success = gx_dblog_error_free_check(logDb, *errorToLog, error); 00327 *errorToLog = NULL; 00328 return success; 00329 } 00330 00331 // Best effort. Invokes EXIT_APPLICATION as the last thing. 00332 void gx_dblog_fatal_error_free(LogDb* logDb, GError* errorToLog) 00333 { 00334 gx_dblog_error_free(logDb, errorToLog); 00335 er_fatal(); 00336 } 00337 00338 // Best effort. Invokes EXIT_APPLICATION as the last thing. 00339 void gx_dblog_fatal_error_clear(LogDb* logDb, GError** errorToLog) 00340 { 00341 gx_dblog_error_clear(logDb, errorToLog); 00342 er_fatal(); 00343 } 00344 00345 // Invokes EXIT_APPLICATION as the last thing. 00346 void gx_txtlog_fatal_error_free(GError* errorToLog) 00347 { 00348 gx_txtlog_error_free(errorToLog); 00349 er_fatal(); 00350 } 00351 00352 void gx_txtlog_fatal_error_clear(GError** errorToLog) 00353 { 00354 gx_txtlog_error_clear(errorToLog); 00355 er_fatal(); 00356 } 00357 00358 // -------------------------------------------------- 00359 // POSIX specific 00360 // -------------------------------------------------- 00361 00362 void px_dblog_fatal_error(LogDb* logDb, int errCode) 00363 { 00364 log_db_log_status(logDb, NULL, "FATAL: POSIX error: %s (%d)", strerror(errCode), errCode); 00365 er_fatal(); 00366 } 00367 00368 void px_dblog_fatal_errno(LogDb* logDb) 00369 { 00370 px_dblog_fatal_error(logDb, errno); 00371 } 00372 00373 void px_txtlog_fatal_error(int errCode) 00374 { 00375 logg("FATAL: POSIX error: %s (%d)", strerror(errCode), errCode); 00376 er_fatal(); 00377 } 00378 00379 void px_txtlog_fatal_errno() 00380 { 00381 px_txtlog_fatal_error(errno); 00382 } 00383 00384 // -------------------------------------------------- 00385 // Symbian specific 00386 // -------------------------------------------------- 00387 00388 #if defined(__SYMBIAN32__) 00389 00390 void ex_fatal_error(int errCode) 00391 { 00392 ex_show_error(errCode); 00393 EXIT_APPLICATION; 00394 } 00395 00396 void ex_txtlog_error(int errCode) 00397 { 00398 logg("ERROR: Symbian error: %s (%d)", plat_error_strerror(errCode), errCode); 00399 } 00400 00401 gboolean ex_dblog_error(LogDb* logDb, int errCode, GError** error) 00402 { 00403 return log_db_log_status(logDb, error, "ERROR: Symbian error: %s (%d)", plat_error_strerror(errCode), errCode); 00404 } 00405 00406 gboolean ex_dblog_error_msg(LogDb* logDb, const char* msg, int errCode, GError** error) 00407 { 00408 return log_db_log_status(logDb, error, "ERROR: %s: %s (%d)", msg, plat_error_strerror(errCode), errCode); 00409 } 00410 00411 void ex_txtlog_fatal_error(int errCode) 00412 { 00413 logg("FATAL: Symbian error: %s (%d)", plat_error_strerror(errCode), errCode); 00414 ex_fatal_error(errCode); 00415 } 00416 00417 void ex_dblog_fatal_error(LogDb* logDb, int errCode) 00418 { 00419 log_db_log_status(logDb, NULL, "FATAL: Symbian error: %s (%d)", plat_error_strerror(errCode), errCode); 00420 ex_fatal_error(errCode); 00421 } 00422 00423 void ex_dblog_fatal_error_msg(LogDb* logDb, const char* msg, int errCode) 00424 { 00425 log_db_log_status(logDb, NULL, "FATAL: %s: %s (%d)", msg, plat_error_strerror(errCode), errCode); 00426 ex_fatal_error(errCode); 00427 } 00428 00429 #endif /* __SYMBIAN32__ */ 00430 00431 /** 00432 00433 er_errors.c 00434 00435 Copyright 2009 Helsinki Institute for Information Technology (HIIT) 00436 and the authors. All rights reserved. 00437 00438 Authors: Tero Hasu <tero.hasu@hut.fi> 00439 00440 Permission is hereby granted, free of charge, to any person 00441 obtaining a copy of this software and associated documentation files 00442 (the "Software"), to deal in the Software without restriction, 00443 including without limitation the rights to use, copy, modify, merge, 00444 publish, distribute, sublicense, and/or sell copies of the Software, 00445 and to permit persons to whom the Software is furnished to do so, 00446 subject to the following conditions: 00447 00448 The above copyright notice and this permission notice shall be 00449 included in all copies or substantial portions of the Software. 00450 00451 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00452 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00453 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00454 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 00455 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 00456 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00457 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00458 SOFTWARE. 00459 00460 **/
ContextLogger2—ContextLogger2 Logger Daemon Internals—Generated on Mon May 2 13:49:52 2011 by Doxygen 1.6.1