er_errors.c

Go to the documentation of this file.
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