X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=errlog.c;h=416b87d4f6014551faf3a87d9d342a9fa8b2ef4e;hp=6afe088b08f96182a2c615ec8531ef09fcbba8d3;hb=9877d948ac98fd6c2d83d9a07d2811676da78bd9;hpb=15aa9900e22693f5fd92d2eb92499909bc061a67 diff --git a/errlog.c b/errlog.c index 6afe088b..416b87d4 100644 --- a/errlog.c +++ b/errlog.c @@ -1,4 +1,4 @@ -const char errlog_rcs[] = "$Id: errlog.c,v 1.61 2007/11/04 19:03:01 fabiankeil Exp $"; +const char errlog_rcs[] = "$Id: errlog.c,v 1.110 2010/07/26 12:11:51 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/errlog.c,v $ @@ -6,7 +6,7 @@ const char errlog_rcs[] = "$Id: errlog.c,v 1.61 2007/11/04 19:03:01 fabiankeil E * Purpose : Log errors to a designated destination in an elegant, * printf-like fashion. * - * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge + * Copyright : Written by and Copyright (C) 2001-2010 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -31,296 +31,14 @@ const char errlog_rcs[] = "$Id: errlog.c,v 1.61 2007/11/04 19:03:01 fabiankeil E * or write to the Free Software Foundation, Inc., 59 * Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - * Revisions : - * $Log: errlog.c,v $ - * Revision 1.61 2007/11/04 19:03:01 fabiankeil - * Fix another deadlock Hal spotted and that mysteriously didn't affect FreeBSD. - * - * Revision 1.60 2007/11/03 19:03:31 fabiankeil - * - Prevent the Windows GUI from showing the version two times in a row. - * - Stop using the imperative in the "(Re-)Open logfile" message. - * - Ditch the "Switching to daemon mode" message as the detection - * whether or not we're already in daemon mode doesn't actually work. - * - * Revision 1.59 2007/11/01 12:50:56 fabiankeil - * Here's looking at you, deadlock. - * - * Revision 1.58 2007/10/28 19:04:21 fabiankeil - * Don't mention daemon mode in "Logging disabled" message. Some - * platforms call it differently and it's not really relevant anyway. - * - * Revision 1.57 2007/10/27 13:02:26 fabiankeil - * Relocate daemon-mode-related log messages to make sure - * they aren't shown again in case of configuration reloads. - * - * Revision 1.56 2007/10/14 14:26:56 fabiankeil - * Remove the old log_error() version. - * - * Revision 1.55 2007/10/14 14:12:41 fabiankeil - * When in daemon mode, close stderr after the configuration file has been - * parsed the first time. If logfile isn't set, stop logging. Fixes BR#897436. - * - * Revision 1.54 2007/09/22 16:15:34 fabiankeil - * - Let it compile with pcc. - * - Move our includes below system includes to prevent macro conflicts. - * - * Revision 1.53 2007/08/05 13:53:14 fabiankeil - * #1763173 from Stefan Huehner: declare some more functions - * static and use void instead of empty parameter lists. - * - * Revision 1.52 2007/07/14 07:28:47 fabiankeil - * Add translation function for JB_ERR_FOO codes. - * - * Revision 1.51 2007/05/11 11:51:34 fabiankeil - * Fix a type mismatch warning. - * - * Revision 1.50 2007/04/11 10:55:44 fabiankeil - * Enforce some assertions that could be triggered - * on mingw32 and other systems where we use threads - * but no locks. - * - * Revision 1.49 2007/04/08 16:44:15 fabiankeil - * We need for gettimeofday(), not . - * - * Revision 1.48 2007/03/31 13:33:28 fabiankeil - * Add alternative log_error() with timestamps - * that contain milliseconds and without using - * strcpy(), strcat() or sprintf(). - * - * Revision 1.47 2006/11/28 15:25:15 fabiankeil - * Only unlink the pidfile if it's actually used. - * - * Revision 1.46 2006/11/13 19:05:51 fabiankeil - * Make pthread mutex locking more generic. Instead of - * checking for OSX and OpenBSD, check for FEATURE_PTHREAD - * and use mutex locking unless there is an _r function - * available. Better safe than sorry. - * - * Fixes "./configure --disable-pthread" and should result - * in less threading-related problems on pthread-using platforms, - * but it still doesn't fix BR#1122404. - * - * Revision 1.45 2006/08/21 11:15:54 david__schmidt - * MS Visual C++ build updates - * - * Revision 1.44 2006/08/18 16:03:16 david__schmidt - * Tweak for OS/2 build happiness. - * - * Revision 1.43 2006/08/03 02:46:41 david__schmidt - * Incorporate Fabian Keil's patch work: - * http://www.fabiankeil.de/sourcecode/privoxy/ - * - * Revision 1.42 2006/07/18 14:48:46 david__schmidt - * Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch) - * with what was really the latest development (the v_3_0_branch branch) - * - * Revision 1.40.2.4 2005/04/03 20:10:50 david__schmidt - * Thanks to Jindrich Makovicka for a race condition fix for the log - * file. The race condition remains for non-pthread implementations. - * Reference patch #1175720. - * - * Revision 1.40.2.3 2003/03/07 03:41:04 david__schmidt - * Wrapping all *_r functions (the non-_r versions of them) with mutex - * semaphores for OSX. Hopefully this will take care of all of those pesky - * crash reports. - * - * Revision 1.40.2.2 2002/09/28 00:30:57 david__schmidt - * Update error logging to give sane values for thread IDs on Mach kernels. - * It's still a hack, but at least it looks farily normal. We print the - * absolute value of the first 4 bytes of the pthread_t modded with 1000. - * - * Revision 1.40.2.1 2002/09/25 12:47:42 oes - * Make log_error safe against NULL string arguments - * - * Revision 1.40 2002/05/22 01:27:27 david__schmidt - * - * Add os2_socket_strerr mirroring w32_socket_strerr. - * - * Revision 1.39 2002/04/03 17:15:27 gliptak - * zero padding thread ids in log - * - * Revision 1.38 2002/03/31 17:18:59 jongfoster - * Win32 only: Enabling STRICT to fix a VC++ compile warning. - * - * Revision 1.37 2002/03/27 14:32:43 david__schmidt - * More compiler warning message maintenance - * - * Revision 1.36 2002/03/26 22:29:54 swa - * we have a new homepage! - * - * Revision 1.35 2002/03/24 15:23:33 jongfoster - * Name changes - * - * Revision 1.34 2002/03/24 13:25:43 swa - * name change related issues - * - * Revision 1.33 2002/03/13 00:27:04 jongfoster - * Killing warnings - * - * Revision 1.32 2002/03/07 03:46:17 oes - * Fixed compiler warnings - * - * Revision 1.31 2002/03/06 23:02:57 jongfoster - * Removing tabs - * - * Revision 1.30 2002/03/05 22:43:45 david__schmidt - * - Better error reporting on OS/2 - * - Fix double-slash comment (oops) - * - * Revision 1.29 2002/03/04 23:45:13 jongfoster - * Printing thread ID if using Win32 native threads - * - * Revision 1.28 2002/03/04 17:59:59 oes - * Deleted deletePidFile(), cosmetics - * - * Revision 1.27 2002/03/04 02:08:01 david__schmidt - * Enable web editing of actions file on OS/2 (it had been broken all this time!) - * - * Revision 1.26 2002/01/09 19:05:45 steudten - * Fix big memory leak. - * - * Revision 1.25 2002/01/09 14:32:08 oes - * Added support for gmtime_r and localtime_r. - * - * Revision 1.24 2001/12/30 14:07:32 steudten - * - Add signal handling (unix) - * - Add SIGHUP handler (unix) - * - Add creation of pidfile (unix) - * - Add action 'top' in rc file (RH) - * - Add entry 'SIGNALS' to manpage - * - Add exit message to logfile (unix) - * - * Revision 1.23 2001/11/07 00:02:13 steudten - * Add line number in error output for lineparsing for - * actionsfile and configfile. - * Special handling for CLF added. - * - * Revision 1.22 2001/11/05 23:43:05 steudten - * Add time+date to log files. - * - * Revision 1.21 2001/10/25 03:40:47 david__schmidt - * Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple - * threads to call select() simultaneously. So, it's time to do a real, live, - * native OS/2 port. See defines for __EMX__ (the porting layer) vs. __OS2__ - * (native). Both versions will work, but using __OS2__ offers multi-threading. - * - * Revision 1.20 2001/09/16 23:04:34 jongfoster - * Fixing a warning - * - * Revision 1.19 2001/09/13 20:08:06 jongfoster - * Adding support for LOG_LEVEL_CGI - * - * Revision 1.18 2001/09/10 11:27:24 oes - * Declaration of w32_socket_strerr now conditional - * - * Revision 1.17 2001/09/10 10:17:13 oes - * Removed unused variable; Fixed sprintf format - * - * Revision 1.16 2001/07/30 22:08:36 jongfoster - * Tidying up #defines: - * - All feature #defines are now of the form FEATURE_xxx - * - Permanently turned off WIN_GUI_EDIT - * - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS - * - * Revision 1.15 2001/07/29 17:41:10 jongfoster - * Now prints thread ID for each message (pthreads only) - * - * Revision 1.14 2001/07/19 19:03:48 haroon - * - Added case for LOG_LEVEL_POPUPS - * - * Revision 1.13 2001/07/13 13:58:58 oes - * - Added case for LOG_LEVEL_DEANIMATE - * - Removed all #ifdef PCRS - * - * Revision 1.12 2001/06/09 10:55:28 jongfoster - * Changing BUFSIZ ==> BUFFER_SIZE - * - * Revision 1.11 2001/06/01 18:14:49 jongfoster - * Changing the calls to strerr() to check HAVE_STRERR (which is defined - * in config.h if appropriate) rather than the NO_STRERR macro. - * - * Revision 1.10 2001/05/29 11:52:21 oes - * Conditional compilation of w32_socket_error - * - * Revision 1.9 2001/05/28 16:15:17 jongfoster - * Improved reporting of errors under Win32. - * - * Revision 1.8 2001/05/26 17:25:14 jongfoster - * Added support for CLF (Common Log Format) and fixed LOG_LEVEL_LOG - * - * Revision 1.7 2001/05/26 15:21:28 jongfoster - * Activity animation in Win32 GUI now works even if debug==0 - * - * Revision 1.6 2001/05/25 21:55:08 jongfoster - * Now cleans up properly on FATAL (removes taskbar icon etc) - * - * Revision 1.5 2001/05/22 18:46:04 oes - * - * - Enabled filtering banners by size rather than URL - * by adding patterns that replace all standard banner - * sizes with the "Junkbuster" gif to the re_filterfile - * - * - Enabled filtering WebBugs by providing a pattern - * which kills all 1x1 images - * - * - Added support for PCRE_UNGREEDY behaviour to pcrs, - * which is selected by the (nonstandard and therefore - * capital) letter 'U' in the option string. - * It causes the quantifiers to be ungreedy by default. - * Appending a ? turns back to greedy (!). - * - * - Added a new interceptor ijb-send-banner, which - * sends back the "Junkbuster" gif. Without imagelist or - * MSIE detection support, or if tinygif = 1, or the - * URL isn't recognized as an imageurl, a lame HTML - * explanation is sent instead. - * - * - Added new feature, which permits blocking remote - * script redirects and firing back a local redirect - * to the browser. - * The feature is conditionally compiled, i.e. it - * can be disabled with --disable-fast-redirects, - * plus it must be activated by a "fast-redirects" - * line in the config file, has its own log level - * and of course wants to be displayed by show-proxy-args - * Note: Boy, all the #ifdefs in 1001 locations and - * all the fumbling with configure.in and acconfig.h - * were *way* more work than the feature itself :-( - * - * - Because a generic redirect template was needed for - * this, tinygif = 3 now uses the same. - * - * - Moved GIFs, and other static HTTP response templates - * to project.h - * - * - Some minor fixes - * - * - Removed some >400 CRs again (Jon, you really worked - * a lot! ;-) - * - * Revision 1.4 2001/05/21 19:32:54 jongfoster - * Added another #ifdef _WIN_CONSOLE - * - * Revision 1.3 2001/05/20 01:11:40 jongfoster - * Added support for LOG_LEVEL_FATAL - * Renamed LOG_LEVEL_FRC to LOG_LEVEL_FORCE, - * and LOG_LEVEL_REF to LOG_LEVEL_RE_FILTER - * - * Revision 1.2 2001/05/17 22:42:01 oes - * - Cleaned CRLF's from the sources and related files - * - Repaired logging for REF and FRC - * - * Revision 1.1.1.1 2001/05/15 13:58:51 oes - * Initial import of version 2.9.3 source tree - * - * *********************************************************************/ - + #include #include #include #include +#include #include "config.h" #include "miscutil.h" @@ -371,8 +89,8 @@ const char errlog_h_rcs[] = ERRLOG_H_VERSION; /* where to log (default: stderr) */ static FILE *logfp = NULL; -/* logging detail level. */ -int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR | LOG_LEVEL_INFO); +/* logging detail level. XXX: stupid name. */ +static int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR); /* static functions */ static void fatal_error(const char * error_message); @@ -383,24 +101,24 @@ static char *w32_socket_strerr(int errcode, char *tmp_buf); static char *os2_socket_strerr(int errcode, char *tmp_buf); #endif -#ifdef FEATURE_PTHREAD +#ifdef MUTEX_LOCKS_AVAILABLE static inline void lock_logfile(void) { - pthread_mutex_lock(&log_mutex); + privoxy_mutex_lock(&log_mutex); } static inline void unlock_logfile(void) { - pthread_mutex_unlock(&log_mutex); + privoxy_mutex_unlock(&log_mutex); } static inline void lock_loginit(void) { - pthread_mutex_lock(&log_init_mutex); + privoxy_mutex_lock(&log_init_mutex); } static inline void unlock_loginit(void) { - pthread_mutex_unlock(&log_init_mutex); + privoxy_mutex_unlock(&log_init_mutex); } -#else /* ! FEATURE_PTHREAD */ +#else /* ! MUTEX_LOCKS_AVAILABLE */ /* * FIXME we need a cross-platform locking mechanism. * The locking/unlocking functions below should be @@ -417,8 +135,8 @@ static inline void unlock_loginit() {} * Function : fatal_error * * Description : Displays a fatal error to standard error (or, on - * a WIN32 GUI, to a dialog box), and exits - * JunkBuster with status code 1. + * a WIN32 GUI, to a dialog box), and exits Privoxy + * with status code 1. * * Parameters : * 1 : error_message = The error message to display. @@ -426,10 +144,17 @@ static inline void unlock_loginit() {} * Returns : Does not return. * *********************************************************************/ -static void fatal_error(const char * error_message) +static void fatal_error(const char *error_message) { #if defined(_WIN32) && !defined(_WIN_CONSOLE) - MessageBox(g_hwndLogFrame, error_message, "Privoxy Error", + /* Skip timestamp and thread id for the message box. */ + const char *box_message = strstr(error_message, "Fatal error"); + if (NULL == box_message) + { + /* Shouldn't happen but ... */ + box_message = error_message; + } + MessageBox(g_hwndLogFrame, box_message, "Privoxy Error", MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST); /* Cleanup - remove taskbar icon etc. */ @@ -464,7 +189,7 @@ static void fatal_error(const char * error_message) * Returns : Nothing. * *********************************************************************/ -static void show_version(const char *prog_name) +void show_version(const char *prog_name) { log_error(LOG_LEVEL_INFO, "Privoxy version " VERSION); if (prog_name != NULL) @@ -488,13 +213,12 @@ static void show_version(const char *prog_name) * Returns : Nothing. * *********************************************************************/ -void init_log_module(const char *prog_name) +void init_log_module(void) { lock_logfile(); logfp = stderr; unlock_logfile(); set_debug_level(debug); - show_version(prog_name); } @@ -506,7 +230,7 @@ void init_log_module(const char *prog_name) * plus LOG_LEVEL_MINIMUM. * * XXX: we should only use the LOG_LEVEL_MINIMUM - * until the frist time the configuration file has + * until the first time the configuration file has * been parsed. * * Parameters : 1: debug_level = The debug level to set. @@ -535,7 +259,8 @@ void disable_logging(void) { if (logfp != NULL) { - log_error(LOG_LEVEL_INFO, "No logfile configured. Logging disabled."); + log_error(LOG_LEVEL_INFO, + "No logfile configured. Please enable it before reporting any problems."); lock_logfile(); fclose(logfp); logfp = NULL; @@ -554,8 +279,7 @@ void disable_logging(void) * * Parameters : * 1 : prog_name = The program name. - * 2 : logfname = The logfile name, or NULL for stderr. - * 3 : debuglevel = The debugging level. + * 2 : logfname = The logfile to (re)open. * * Returns : N/A * @@ -568,13 +292,44 @@ void init_error_log(const char *prog_name, const char *logfname) lock_loginit(); - if (logfp != NULL) + if ((logfp != NULL) && (logfp != stderr)) { log_error(LOG_LEVEL_INFO, "(Re-)Opening logfile \'%s\'", logfname); } /* set the designated log file */ fp = fopen(logfname, "a"); + if ((NULL == fp) && (logfp != NULL)) + { + /* + * Some platforms (like OS/2) don't allow us to open + * the same file twice, therefore we give it another + * shot after closing the old file descriptor first. + * + * We don't do it right away because it prevents us + * from logging the "can't open logfile" message to + * the old logfile. + * + * XXX: this is a lame workaround and once the next + * release is out we should stop bothering reopening + * the logfile unless we have to. + * + * Currently we reopen it every time the config file + * has been reloaded, but actually we only have to + * reopen it if the file name changed or if the + * configuration reload was caused by a SIGHUP. + */ + log_error(LOG_LEVEL_INFO, "Failed to reopen logfile: \'%s\'. " + "Retrying after closing the old file descriptor first. If that " + "doesn't work, Privoxy will exit without being able to log a message.", + logfname); + lock_logfile(); + fclose(logfp); + logfp = NULL; + unlock_logfile(); + fp = fopen(logfname, "a"); + } + if (NULL == fp) { log_error(LOG_LEVEL_FATAL, "init_error_log(): can't open logfile: \'%s\'", logfname); @@ -588,21 +343,25 @@ void init_error_log(const char *prog_name, const char *logfname) { fclose(logfp); } +#ifdef unix + if (daemon_mode && (logfp == stderr)) + { + if (dup2(1, 2) == -1) + { + /* + * We only use fatal_error() to clear the pid + * file and to exit. Given that stderr has just + * been closed, the user will not see the error + * message. + */ + fatal_error("Failed to reserve fd 2."); + } + } +#endif logfp = fp; unlock_logfile(); -#if !defined(_WIN32) - /* - * Prevent the Windows GUI from showing the version two - * times in a row on startup. It already displayed the show_version() - * call from init_log_module() that other systems write to stderr. - * - * This means mingw32 users will never see the version in their - * log file, but I assume they wouldn't look for it there anyway - * and simply use the "Help/About Privoxy" menu. - */ show_version(prog_name); -#endif /* def unix */ unlock_loginit(); @@ -679,21 +438,20 @@ static inline size_t get_log_timestamp(char *buffer, size_t buffer_size) gettimeofday(&tv_now, NULL); msecs = tv_now.tv_usec / 1000; - - time(&now); + now = tv_now.tv_sec; #ifdef HAVE_LOCALTIME_R tm_now = *localtime_r(&now, &tm_now); -#elif FEATURE_PTHREAD - pthread_mutex_lock(&localtime_mutex); +#elif defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_lock(&localtime_mutex); tm_now = *localtime(&now); - pthread_mutex_unlock(&localtime_mutex); + privoxy_mutex_unlock(&localtime_mutex); #else tm_now = *localtime(&now); #endif - length = strftime(buffer, buffer_size, "%b %d %H:%M:%S", &tm_now); - if (length > 0); + length = strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", &tm_now); + if (length > (size_t)0) { msecs_length = snprintf(buffer+length, buffer_size - length, ".%.3ld", msecs); } @@ -742,19 +500,19 @@ static inline size_t get_clf_timestamp(char *buffer, size_t buffer_size) time (&now); #ifdef HAVE_GMTIME_R gmt = *gmtime_r(&now, &gmt); -#elif FEATURE_PTHREAD - pthread_mutex_lock(&gmtime_mutex); +#elif defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_lock(&gmtime_mutex); gmt = *gmtime(&now); - pthread_mutex_unlock(&gmtime_mutex); + privoxy_mutex_unlock(&gmtime_mutex); #else gmt = *gmtime(&now); #endif #ifdef HAVE_LOCALTIME_R tm_now = localtime_r(&now, &dummy); -#elif FEATURE_PTHREAD - pthread_mutex_lock(&localtime_mutex); +#elif defined(MUTEX_LOCKS_AVAILABLE) + privoxy_mutex_lock(&localtime_mutex); tm_now = localtime(&now); - pthread_mutex_unlock(&localtime_mutex); + privoxy_mutex_unlock(&localtime_mutex); #else tm_now = localtime(&now); #endif @@ -764,7 +522,7 @@ static inline size_t get_clf_timestamp(char *buffer, size_t buffer_size) length = strftime(buffer, buffer_size, "%d/%b/%Y:%H:%M:%S ", tm_now); - if (length > 0); + if (length > (size_t)0) { tz_length = snprintf(buffer+length, buffer_size-length, "%+03d%02d", mins / 60, abs(mins) % 60); @@ -814,9 +572,12 @@ static inline const char *get_log_level_string(int loglevel) case LOG_LEVEL_CONNECT: log_level_string = "Connect"; break; - case LOG_LEVEL_LOG: + case LOG_LEVEL_WRITING: log_level_string = "Writing"; break; + case LOG_LEVEL_RECEIVED: + log_level_string = "Received"; + break; case LOG_LEVEL_HEADER: log_level_string = "Header"; break; @@ -831,19 +592,15 @@ static inline const char *get_log_level_string(int loglevel) log_level_string = "Force"; break; #endif /* def FEATURE_FORCE_LOAD */ -#ifdef FEATURE_FAST_REDIRECTS case LOG_LEVEL_REDIRECTS: log_level_string = "Redirect"; break; -#endif /* def FEATURE_FAST_REDIRECTS */ case LOG_LEVEL_DEANIMATE: log_level_string = "Gif-Deanimate"; break; -#ifdef FEATURE_KILL_POPUPS - case LOG_LEVEL_POPUPS: - log_level_string = "Kill-Popups"; + case LOG_LEVEL_CRUNCH: + log_level_string = "Crunch"; break; -#endif /* def FEATURE_KILL_POPUPS */ case LOG_LEVEL_CGI: log_level_string = "CGI"; break; @@ -894,7 +651,7 @@ void log_error(int loglevel, const char *fmt, ...) * the taskbar icon animate. (There is an option to disable * this but checking that is handled inside LogShowActivity()). */ - if (loglevel == LOG_LEVEL_GPC) + if ((loglevel == LOG_LEVEL_GPC) || (loglevel == LOG_LEVEL_CRUNCH)) { LogShowActivity(); } @@ -905,9 +662,17 @@ void log_error(int loglevel, const char *fmt, ...) * settings and that logging is enabled. * Bail out otherwise. */ - if ((loglevel != LOG_LEVEL_FATAL) && - ((0 == (loglevel & debug)) || (logfp == NULL))) + if ((0 == (loglevel & debug)) +#ifndef _WIN32 + || (logfp == NULL) +#endif + ) { + if (loglevel == LOG_LEVEL_FATAL) + { + fatal_error("Fatal error. You're not supposed to" + "see this message. Please file a bug report."); + } return; } @@ -923,9 +688,10 @@ void log_error(int loglevel, const char *fmt, ...) if (NULL == outbuf_save) { snprintf(tempbuf, sizeof(tempbuf), - "%s Privoxy(%08lx) Fatal error: log_error() failed to allocate buffer memory.\n" - "\nExiting.", timestamp, thread_id); + "%s %08lx Fatal error: Out of memory in log_error().", + timestamp, thread_id); fatal_error(tempbuf); /* Exit */ + return; } } outbuf = outbuf_save; @@ -939,8 +705,8 @@ void log_error(int loglevel, const char *fmt, ...) /* Add prefix for everything but Common Log Format messages */ if (loglevel != LOG_LEVEL_CLF) { - length = (size_t)snprintf(outbuf, log_buffer_size, "%s Privoxy(%08lx) %s: ", - timestamp, thread_id, get_log_level_string(loglevel)); + length = (size_t)snprintf(outbuf, log_buffer_size, "%s %08lx %s: ", + timestamp, thread_id, get_log_level_string(loglevel)); } /* get ready to scan var. args. */ @@ -962,9 +728,9 @@ void log_error(int loglevel, const char *fmt, ...) { outbuf[length++] = ch; /* - * XXX: Only necessary on platforms which don't use pthread - * mutexes (mingw32 for example), where multiple threads can - * write to the buffer at the same time. + * XXX: Only necessary on platforms where multiple threads + * can write to the buffer at the same time because we + * don't support mutexes (OS/2 for example). */ outbuf[length] = '\0'; continue; @@ -985,7 +751,7 @@ void log_error(int loglevel, const char *fmt, ...) snprintf(tempbuf, sizeof(tempbuf), "%u", uval); break; case 'l': - /* this is a modifier that must be followed by u or d */ + /* this is a modifier that must be followed by u, lu, or d */ ch = *src++; if (ch == 'd') { @@ -997,6 +763,12 @@ void log_error(int loglevel, const char *fmt, ...) ulval = va_arg( ap, unsigned long ); snprintf(tempbuf, sizeof(tempbuf), "%lu", ulval); } + else if ((ch == 'l') && (*src == 'u')) + { + unsigned long long lluval = va_arg(ap, unsigned long long); + snprintf(tempbuf, sizeof(tempbuf), "%llu", lluval); + src++; + } else { snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt); @@ -1020,45 +792,36 @@ void log_error(int loglevel, const char *fmt, ...) break; case 'N': /* - * Non-standard: Print a counted unterminated string. + * Non-standard: Print a counted unterminated string, + * replacing unprintable bytes with their hex value. * Takes 2 parameters: int length, const char * string. */ ival = va_arg(ap, int); + assert(ival >= 0); sval = va_arg(ap, char *); - if (sval == NULL) - { - format_string = "[null]"; - } - else if (ival <= 0) + assert(sval != NULL); + + while ((ival-- > 0) && (length < log_buffer_size - 6)) { - if (0 == ival) + if (isprint((int)*sval) && (*sval != '\\')) { - /* That's ok (but stupid) */ - tempbuf[0] = '\0'; + outbuf[length++] = *sval; + outbuf[length] = '\0'; } else { - /* - * That's not ok (and even more stupid) - */ - assert(ival >= 0); - format_string = "[counted string lenght < 0]"; + int ret = snprintf(outbuf + length, + log_buffer_size - length - 2, "\\x%.2x", (unsigned char)*sval); + assert(ret == 4); + length += 4; } + sval++; } - else if (ival >= sizeof(tempbuf)) - { - /* - * String is too long, copy as much as possible. - * It will be further truncated later. - */ - memcpy(tempbuf, sval, sizeof(tempbuf)-1); - tempbuf[sizeof(tempbuf)-1] = '\0'; - } - else - { - memcpy(tempbuf, sval, (size_t) ival); - tempbuf[ival] = '\0'; - } + /* + * XXX: In case of printable characters at the end of + * the %N string, we're not using the whole buffer. + */ + format_string = (length < log_buffer_size - 6) ? "" : "[too long]"; break; case 'E': /* Non-standard: Print error code from errno */ @@ -1097,14 +860,14 @@ void log_error(int loglevel, const char *fmt, ...) snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt); loglevel = LOG_LEVEL_FATAL; break; - } /* switch( p ) */ + } assert(length < log_buffer_size); length += strlcpy(outbuf + length, format_string, log_buffer_size - length); if (length >= log_buffer_size-2) { - static char warning[] = "... [too long, truncated]"; + static const char warning[] = "... [too long, truncated]"; length = log_buffer_size - sizeof(warning) - 1; length += strlcpy(outbuf + length, warning, log_buffer_size - length); @@ -1112,7 +875,7 @@ void log_error(int loglevel, const char *fmt, ...) break; } - } /* for( p ... ) */ + } /* done with var. args */ va_end(ap); @@ -1121,9 +884,9 @@ void log_error(int loglevel, const char *fmt, ...) length += strlcpy(outbuf + length, "\n", log_buffer_size - length); /* Some sanity checks */ - if (!(length < log_buffer_size) - || !(outbuf[log_buffer_size-1] == '\0') - || !(outbuf[log_buffer_size] == '\0') + if ((length >= log_buffer_size) + || (outbuf[log_buffer_size-1] != '\0') + || (outbuf[log_buffer_size] != '\0') ) { /* Repeat as assertions */ @@ -1137,27 +900,37 @@ void log_error(int loglevel, const char *fmt, ...) assert(outbuf[log_buffer_size] == '\0'); snprintf(outbuf, log_buffer_size, - "%s Privoxy(%08lx) Fatal error: log_error()'s sanity checks failed. length: %d\n" - "Exiting.", timestamp, thread_id, (int)length); + "%s %08lx Fatal error: log_error()'s sanity checks failed." + "length: %d. Exiting.", + timestamp, thread_id, (int)length); loglevel = LOG_LEVEL_FATAL; } - assert(NULL != logfp || loglevel == LOG_LEVEL_FATAL); +#ifndef _WIN32 + /* + * On Windows this is acceptable in case + * we are logging to the GUI window only. + */ + assert(NULL != logfp); +#endif if (loglevel == LOG_LEVEL_FATAL) { fatal_error(outbuf_save); /* Never get here */ } - fputs(outbuf_save, logfp); - - unlock_logfile(); + if (logfp != NULL) + { + fputs(outbuf_save, logfp); + } #if defined(_WIN32) && !defined(_WIN_CONSOLE) /* Write to display */ LogPutString(outbuf_save); #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */ + unlock_logfile(); + } @@ -1172,14 +945,14 @@ void log_error(int loglevel, const char *fmt, ...) * visible to all files that include errlog.h. * * Parameters : - * 1 : error = a valid jb_err code + * 1 : jb_error = a valid jb_err code * * Returns : A string with the jb_err translation * *********************************************************************/ -const char *jb_err_to_string(int error) +const char *jb_err_to_string(int jb_error) { - switch (error) + switch (jb_error) { case JB_ERR_OK: return "Success, no error";