-const char errlog_rcs[] = "$Id: errlog.c,v 1.49 2007/04/08 16:44:15 fabiankeil Exp $";
+const char errlog_rcs[] = "$Id: errlog.c,v 1.85 2009/02/06 17:51:38 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/errlog.c,v $
* 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-2009 the SourceForge
* Privoxy team. http://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
*
* Revisions :
* $Log: errlog.c,v $
+ * Revision 1.85 2009/02/06 17:51:38 fabiankeil
+ * Be prepared if I break the log module initialization again.
+ *
+ * Revision 1.84 2008/12/14 15:46:22 fabiankeil
+ * Give crunched requests their own log level.
+ *
+ * Revision 1.83 2008/12/04 18:14:32 fabiankeil
+ * Fix some cparser warnings.
+ *
+ * Revision 1.82 2008/11/23 16:06:58 fabiankeil
+ * Update a log message I missed in 1.80.
+ *
+ * Revision 1.81 2008/11/23 15:59:27 fabiankeil
+ * - Update copyright range.
+ * - Remove stray line breaks in a log message
+ * nobody is supposed to see anyway.
+ *
+ * Revision 1.80 2008/11/23 15:49:49 fabiankeil
+ * In log_error(), don't surround the thread id with "Privoxy(" and ")".
+ *
+ * Revision 1.79 2008/10/20 17:09:25 fabiankeil
+ * Update init_error_log() description to match reality.
+ *
+ * Revision 1.78 2008/09/07 16:59:31 fabiankeil
+ * Update a comment to reflect that we
+ * have mutex support on mingw32 now.
+ *
+ * Revision 1.77 2008/09/07 12:43:44 fabiankeil
+ * Move the LogPutString() call in log_error() into the locked
+ * region so the Windows GUI log is consistent with the logfile.
+ *
+ * Revision 1.76 2008/09/07 12:35:05 fabiankeil
+ * Add mutex lock support for _WIN32.
+ *
+ * Revision 1.75 2008/09/04 08:13:58 fabiankeil
+ * Prepare for critical sections on Windows by adding a
+ * layer of indirection before the pthread mutex functions.
+ *
+ * Revision 1.74 2008/08/06 18:33:36 fabiankeil
+ * If the "close fd first" workaround doesn't work,
+ * the fatal error message will be lost, so we better
+ * explain the consequences while we still can.
+ *
+ * Revision 1.73 2008/08/04 19:06:55 fabiankeil
+ * Add a lame workaround for the "can't open an already open
+ * logfile on OS/2" problem reported by Maynard in #2028842
+ * and describe what a real solution would look like.
+ *
+ * Revision 1.72 2008/07/27 12:04:28 fabiankeil
+ * Fix a comment typo.
+ *
+ * Revision 1.71 2008/06/28 17:17:15 fabiankeil
+ * Remove another stray semicolon.
+ *
+ * Revision 1.70 2008/06/28 17:10:29 fabiankeil
+ * Remove stray semicolon in get_log_timestamp().
+ * Reported by Jochen Voss in #2005221.
+ *
+ * Revision 1.69 2008/05/30 15:55:25 fabiankeil
+ * Declare variable "debug" static and complain about its name.
+ *
+ * Revision 1.68 2008/04/27 16:50:46 fabiankeil
+ * Remove an incorrect assertion. The value of debug may change if
+ * the configuration is reloaded in another thread. While we could
+ * cache the initial value, the assertion doesn't seem worth it.
+ *
+ * Revision 1.67 2008/03/27 18:27:23 fabiankeil
+ * Remove kill-popups action.
+ *
+ * Revision 1.66 2008/01/31 15:38:14 fabiankeil
+ * - Make the logfp assertion more strict. As of 1.63, the "||" could
+ * have been an "&&", which means we can use two separate assertions
+ * and skip on of them on Windows.
+ * - Break a long commit message line in two.
+ *
+ * Revision 1.65 2008/01/31 14:44:33 fabiankeil
+ * Use (a != b) instead of !(a == b) so the sanity check looks less insane.
+ *
+ * Revision 1.64 2008/01/21 18:56:46 david__schmidt
+ * Swap #def from negative to positive, re-joined it so it didn't
+ * span an assertion (compilation failure on OS/2)
+ *
+ * Revision 1.63 2007/12/15 19:49:32 fabiankeil
+ * Stop overloading logfile to control the mingw32 log window as well.
+ * It's no longer necessary now that we disable all debug lines by default
+ * and at least one user perceived it as a regression (added in 1.55).
+ *
+ * Revision 1.62 2007/11/30 15:33:46 fabiankeil
+ * Unbreak LOG_LEVEL_FATAL. It wasn't fatal with logging disabled
+ * and on mingw32 fatal log messages didn't end up in the log file.
+ *
+ * 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 <sys/time.h> for gettimeofday(), not <time.h>.
*
*********************************************************************/
\f
-#include "config.h"
-#include "miscutil.h"
-
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
-#if defined(HAVE_STRLCPY) && defined(HAVE_GETTIMEOFDAY)
-#define USE_NEW_LOG_ERROR
+#include "config.h"
+#include "miscutil.h"
+
/* For gettimeofday() */
#include <sys/time.h>
-#endif /* defined(HAVE_STRLCPY) && defined(HAVE_GETTIMEOFDAY) */
#if !defined(_WIN32) && !defined(__OS2__)
#include <unistd.h>
/* 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 | LOG_LEVEL_INFO);
/* static functions */
static void fatal_error(const char * error_message);
static char *os2_socket_strerr(int errcode, char *tmp_buf);
#endif
-#ifdef FEATURE_PTHREAD
-static inline void lock_logfile()
+#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()
+static inline void unlock_logfile(void)
{
- pthread_mutex_unlock(&log_mutex);
+ privoxy_mutex_unlock(&log_mutex);
}
-static inline void lock_loginit()
+static inline void lock_loginit(void)
{
- pthread_mutex_lock(&log_init_mutex);
+ privoxy_mutex_lock(&log_init_mutex);
}
-static inline void unlock_loginit()
+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
/* Cleanup - remove taskbar icon etc. */
TermLogWindow();
-
-#else /* if !defined(_WIN32) || defined(_WIN_CONSOLE) */
- fputs(error_message, stderr);
#endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
+ if (logfp != NULL)
+ {
+ fputs(error_message, logfp);
+ }
+
#if defined(unix)
- if(pidfile)
+ if (pidfile)
{
unlink(pidfile);
}
}
+/*********************************************************************
+ *
+ * Function : show_version
+ *
+ * Description : Logs the Privoxy version and the program name.
+ *
+ * Parameters :
+ * 1 : prog_name = The program name.
+ *
+ * Returns : Nothing.
+ *
+ *********************************************************************/
+void show_version(const char *prog_name)
+{
+ log_error(LOG_LEVEL_INFO, "Privoxy version " VERSION);
+ if (prog_name != NULL)
+ {
+ log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
+ }
+}
+
+
+/*********************************************************************
+ *
+ * Function : init_log_module
+ *
+ * Description : Initializes the logging module to log to stderr.
+ * Can only be called while stderr hasn't been closed
+ * yet and is only supposed to be called once.
+ *
+ * Parameters :
+ * 1 : prog_name = The program name.
+ *
+ * Returns : Nothing.
+ *
+ *********************************************************************/
+void init_log_module(void)
+{
+ lock_logfile();
+ logfp = stderr;
+ unlock_logfile();
+ set_debug_level(debug);
+}
+
+
+/*********************************************************************
+ *
+ * Function : set_debug_level
+ *
+ * Description : Sets the debug level to the provided value
+ * plus LOG_LEVEL_MINIMUM.
+ *
+ * XXX: we should only use the LOG_LEVEL_MINIMUM
+ * until the first time the configuration file has
+ * been parsed.
+ *
+ * Parameters : 1: debug_level = The debug level to set.
+ *
+ * Returns : Nothing.
+ *
+ *********************************************************************/
+void set_debug_level(int debug_level)
+{
+ debug = debug_level | LOG_LEVEL_MINIMUM;
+}
+
+
+/*********************************************************************
+ *
+ * Function : disable_logging
+ *
+ * Description : Disables logging.
+ *
+ * Parameters : None.
+ *
+ * Returns : Nothing.
+ *
+ *********************************************************************/
+void disable_logging(void)
+{
+ if (logfp != NULL)
+ {
+ log_error(LOG_LEVEL_INFO,
+ "No logfile configured. Please enable it before reporting any problems.");
+ lock_logfile();
+ fclose(logfp);
+ logfp = NULL;
+ unlock_logfile();
+ }
+}
+
+
/*********************************************************************
*
* Function : init_error_log
*
- * Description : Initializes the logging module. Must call before
- * calling log_error.
+ * Description : Initializes the logging module to log to a file.
+ *
+ * XXX: should be renamed.
*
* 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
*
*********************************************************************/
-void init_error_log(const char *prog_name, const char *logfname, int debuglevel)
+void init_error_log(const char *prog_name, const char *logfname)
{
FILE *fp;
- lock_loginit();
+ assert(NULL != logfname);
- /* set the logging detail level */
- debug = debuglevel | LOG_LEVEL_MINIMUM;
+ lock_loginit();
- if ((logfp != NULL) && (logfp != stderr))
+ if (logfp != NULL)
{
- log_error(LOG_LEVEL_INFO, "(Re-)Open logfile %s", logfname ? logfname : "none");
- lock_logfile();
- fclose(logfp);
- } else {
- lock_logfile();
+ log_error(LOG_LEVEL_INFO, "(Re-)Opening logfile \'%s\'", logfname);
}
- logfp = stderr;
- unlock_logfile();
/* set the designated log file */
- if( logfname )
+ fp = fopen(logfname, "a");
+ if ((NULL == fp) && (logfp != NULL))
{
- if( NULL == (fp = fopen(logfname, "a")) )
- {
- log_error(LOG_LEVEL_FATAL, "init_error_log(): can't open logfile: %s", logfname);
- }
-
- /* set logging to be completely unbuffered */
- setbuf(fp, 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 reloas 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();
- logfp = fp;
+ fclose(logfp);
+ logfp = NULL;
unlock_logfile();
+ fp = fopen(logfname, "a");
}
- log_error(LOG_LEVEL_INFO, "Privoxy version " VERSION);
- if (prog_name != NULL)
+ if (NULL == fp)
{
- log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
+ log_error(LOG_LEVEL_FATAL, "init_error_log(): can't open logfile: \'%s\'", logfname);
}
+ /* set logging to be completely unbuffered */
+ setbuf(fp, NULL);
+
+ lock_logfile();
+ if (logfp != NULL)
+ {
+ fclose(logfp);
+ }
+ 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 main() 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();
} /* init_error_log */
-#if defined(USE_NEW_LOG_ERROR)
-/*
- * Use an alternative log_error version and its helper functions.
- *
- * The code is mostly copied from the old log_error
- * function but it's divided into multiple functions,
- * doesn't use strcpy, strcat or sprintf and compiles
- * with gcc43 without warnings (on FreeBSD that is).
- *
- * It should behave like the old log_error function with
- * two exceptions:
- *
- * - too long format strings are logged truncated instead
- * of completely replaced with the truncation warning,
- * - its time stamps contain milliseconds.
- */
/*********************************************************************
*
* Returns : thread_id
*
*********************************************************************/
-long get_thread_id(void)
+static long get_thread_id(void)
{
long this_thread = 1; /* was: pthread_t this_thread;*/
time_t now;
struct tm tm_now;
struct timeval tv_now; /* XXX: stupid name */
- gettimeofday(&tv_now, NULL);
- long msecs = tv_now.tv_usec / 1000;
+ long msecs;
int msecs_length = 0;
+ gettimeofday(&tv_now, NULL);
+ msecs = tv_now.tv_usec / 1000;
+
time(&now);
#ifdef HAVE_LOCALTIME_R
tm_now = *localtime_r(&now, &tm_now);
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&localtime_mutex);
+ 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);
+ if (length > (size_t)0)
{
msecs_length = snprintf(buffer+length, buffer_size - length, ".%.3ld", msecs);
}
#ifdef HAVE_GMTIME_R
gmt = *gmtime_r(&now, &gmt);
#elif FEATURE_PTHREAD
- pthread_mutex_lock(&gmtime_mutex);
+ 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);
+ 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, "%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);
* Returns : Log level string.
*
*********************************************************************/
-inline const char *get_log_level_string(int loglevel)
+static inline const char *get_log_level_string(int loglevel)
{
char *log_level_string = NULL;
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;
* 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();
}
#endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
- /* verify if loglevel applies to current settings and bail out if negative */
- if ((loglevel & debug) == 0)
+ /*
+ * verify that the loglevel applies to current
+ * settings and that logging is enabled.
+ * Bail out otherwise.
+ */
+ 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;
}
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);
- if( !logfp )
- {
- logfp = stderr;
- }
- fputs(tempbuf, logfp);
- unlock_logfile();
+ "%s %08lx Fatal error: Out of memory in log_error().",
+ timestamp, thread_id);
fatal_error(tempbuf); /* Exit */
}
}
/* 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. */
{
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;
format_string = "[counted string lenght < 0]";
}
}
- else if (ival >= sizeof(tempbuf))
+ else if ((size_t)ival >= sizeof(tempbuf))
{
/*
* String is too long, copy as much as possible.
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 */
assert(outbuf[log_buffer_size] == '\0');
snprintf(outbuf, log_buffer_size,
- "%s Privoxy(%08lx) Fatal error: log_error()'s sanity checks failed. length: %u\n"
- "Exiting.", timestamp, thread_id, length);
+ "%s %08lx Fatal error: log_error()'s sanity checks failed."
+ "length: %d. Exiting.",
+ timestamp, thread_id, (int)length);
loglevel = LOG_LEVEL_FATAL;
}
- /* deal with glibc stupidity - it won't let you initialize logfp */
- /* XXX: Still necessary? */
- if(NULL == logfp)
- {
- logfp = stderr;
- }
-
- fputs(outbuf_save, logfp);
+#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 */
}
-
- 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();
+
}
-#else /* use traditional log_error version */
/*********************************************************************
*
- * Function : log_error
+ * Function : jb_err_to_string
*
- * Description : This is the error-reporting and logging function.
+ * Description : Translates JB_ERR_FOO codes into strings.
+ *
+ * XXX: the type of error codes is jb_err
+ * but the typedef'inition is currently not
+ * visible to all files that include errlog.h.
*
* Parameters :
- * 1 : loglevel = the type of message to be logged
- * 2 : fmt = the main string we want logged, printf-like
- * 3 : ... = arguments to be inserted in fmt (printf-like).
+ * 1 : error = a valid jb_err code
*
- * Returns : N/A
+ * Returns : A string with the jb_err translation
*
*********************************************************************/
-void log_error(int loglevel, const char *fmt, ...)
+const char *jb_err_to_string(int error)
{
- va_list ap;
- char *outbuf= NULL;
- static char *outbuf_save = NULL;
- const char * src = fmt;
- int outc = 0;
- long this_thread = 1; /* was: pthread_t this_thread;*/
-#ifdef __OS2__
- PTIB ptib;
- APIRET ulrc;
-#endif /* __OS2__ */
-
-#if defined(_WIN32) && !defined(_WIN_CONSOLE)
- /*
- * Irrespective of debug setting, a GET/POST/CONNECT makes
- * the taskbar icon animate. (There is an option to disable
- * this but checking that is handled inside LogShowActivity()).
- */
- if (loglevel == LOG_LEVEL_GPC)
+ switch (error)
{
- LogShowActivity();
- }
-#endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
-
- /* verify if loglevel applies to current settings and bail out if negative */
- if ((loglevel & debug) == 0)
- {
- return;
- }
-
- /* protect the whole function because of the static buffer (outbuf) */
- lock_logfile();
-
- /* FIXME get current thread id */
-#ifdef FEATURE_PTHREAD
- this_thread = (long)pthread_self();
-#ifdef __MACH__
- /*
- * Mac OSX (and perhaps other Mach instances) doesn't have a debuggable
- * value at the first 4 bytes of pthread_self()'s return value, a pthread_t.
- * pthread_t is supposed to be opaque... but it's fairly random, though, so
- * we make it mostly presentable.
- */
- this_thread = abs(this_thread % 1000);
-#endif /* def __MACH__ */
-#elif defined(_WIN32)
- this_thread = GetCurrentThreadId();
-#elif defined(__OS2__)
- ulrc = DosGetInfoBlocks(&ptib, NULL);
- if (ulrc == 0)
- this_thread = ptib -> tib_ptib2 -> tib2_ultid;
-#endif /* def FEATURE_PTHREAD */
-
- if ( !outbuf_save )
- {
- outbuf_save = outbuf = (char*)malloc(BUFFER_SIZE);
- if (NULL == outbuf_save)
- {
- fatal_error("Privoxy failed to allocate log buffer.");
- }
- }
- outbuf = outbuf_save;
-
- {
- /*
- * Write timestamp into tempbuf.
- *
- * Complex because not all OSs have tm_gmtoff or
- * the %z field in strftime()
- */
- time_t now;
- struct tm tm_now;
- time (&now);
-#ifdef HAVE_LOCALTIME_R
- tm_now = *localtime_r(&now, &tm_now);
-#elif FEATURE_PTHREAD
- pthread_mutex_lock(&localtime_mutex);
- tm_now = *localtime (&now);
- pthread_mutex_unlock(&localtime_mutex);
-#else
- tm_now = *localtime (&now);
-#endif
- strftime(outbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now);
- outbuf += strlen( outbuf );
- }
- switch (loglevel)
- {
- case LOG_LEVEL_ERROR:
- outc = sprintf(outbuf, "Privoxy(%08lx) Error: ", this_thread);
- break;
- case LOG_LEVEL_FATAL:
- outc = sprintf(outbuf, "Privoxy(%08lx) Fatal error: ", this_thread);
- break;
- case LOG_LEVEL_GPC:
- outc = sprintf(outbuf, "Privoxy(%08lx) Request: ", this_thread);
- break;
- case LOG_LEVEL_CONNECT:
- outc = sprintf(outbuf, "Privoxy(%08lx) Connect: ", this_thread);
- break;
- case LOG_LEVEL_LOG:
- outc = sprintf(outbuf, "Privoxy(%08lx) Writing: ", this_thread);
- break;
- case LOG_LEVEL_HEADER:
- outc = sprintf(outbuf, "Privoxy(%08lx) Header: ", this_thread);
- break;
- case LOG_LEVEL_INFO:
- outc = sprintf(outbuf, "Privoxy(%08lx) Info: ", this_thread);
- break;
- case LOG_LEVEL_RE_FILTER:
- outc = sprintf(outbuf, "Privoxy(%08lx) Re-Filter: ", this_thread);
- break;
-#ifdef FEATURE_FORCE_LOAD
- case LOG_LEVEL_FORCE:
- outc = sprintf(outbuf, "Privoxy(%08lx) Force: ", this_thread);
- break;
-#endif /* def FEATURE_FORCE_LOAD */
-#ifdef FEATURE_FAST_REDIRECTS
- case LOG_LEVEL_REDIRECTS:
- outc = sprintf(outbuf, "Privoxy(%08lx) Redirect: ", this_thread);
- break;
-#endif /* def FEATURE_FAST_REDIRECTS */
- case LOG_LEVEL_DEANIMATE:
- outc = sprintf(outbuf, "Privoxy(%08lx) Gif-Deanimate: ", this_thread);
- break;
- case LOG_LEVEL_CLF:
- outbuf = outbuf_save;
- outc = 0;
- outbuf[0] = '\0';
- break;
-#ifdef FEATURE_KILL_POPUPS
- case LOG_LEVEL_POPUPS:
- outc = sprintf(outbuf, "Privoxy(%08lx) Kill-Popups: ", this_thread);
- break;
-#endif /* def FEATURE_KILL_POPUPS */
- case LOG_LEVEL_CGI:
- outc = sprintf(outbuf, "Privoxy(%08lx) CGI: ", this_thread);
- break;
+ case JB_ERR_OK:
+ return "Success, no error";
+ case JB_ERR_MEMORY:
+ return "Out of memory";
+ case JB_ERR_CGI_PARAMS:
+ return "Missing or corrupt CGI parameters";
+ case JB_ERR_FILE:
+ return "Error opening, reading or writing a file";
+ case JB_ERR_PARSE:
+ return "Parse error";
+ case JB_ERR_MODIFIED:
+ return "File has been modified outside of the CGI actions editor.";
+ case JB_ERR_COMPRESS:
+ return "(De)compression failure";
default:
- outc = sprintf(outbuf, "Privoxy(%08lx) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
- break;
+ assert(0);
+ return "Unknown error";
}
-
- /* get ready to scan var. args. */
- va_start( ap, fmt );
-
- /* build formatted message from fmt and var-args */
- while ((*src) && (outc < BUFFER_SIZE-2))
- {
- char tempbuf[BUFFER_SIZE];
- char *sval = NULL;
- int ival;
- unsigned uval;
- long lval;
- unsigned long ulval;
- int oldoutc;
- char ch;
-
- ch = *src++;
- if( ch != '%' )
- {
- outbuf[outc++] = ch;
- continue;
- }
-
- ch = *src++;
- switch (ch) {
- case '%':
- outbuf[outc++] = '%';
- break;
- case 'd':
- ival = va_arg( ap, int );
- oldoutc = outc;
- outc += sprintf(tempbuf, "%d", ival);
- if (outc < BUFFER_SIZE-1)
- {
- strcpy(outbuf + oldoutc, tempbuf);
- }
- else
- {
- outbuf[oldoutc] = '\0';
- }
- break;
- case 'u':
- uval = va_arg( ap, unsigned );
- oldoutc = outc;
- outc += sprintf(tempbuf, "%u", uval);
- if (outc < BUFFER_SIZE-1)
- {
- strcpy(outbuf + oldoutc, tempbuf);
- }
- else
- {
- outbuf[oldoutc] = '\0';
- }
- break;
- case 'l':
- /* this is a modifier that must be followed by u or d */
- ch = *src++;
- if (ch == 'd')
- {
- lval = va_arg( ap, long );
- oldoutc = outc;
- outc += sprintf(tempbuf, "%ld", lval);
- }
- else if (ch == 'u')
- {
- ulval = va_arg( ap, unsigned long );
- oldoutc = outc;
- outc += sprintf(tempbuf, "%lu", ulval);
- }
- else
- {
- /* Error */
- sprintf(outbuf, "Privoxy(%08lx) Error: log_error(): Bad format string:\n"
- "Format = \"%s\"\n"
- "Exiting.", this_thread, fmt);
- if( !logfp )
- {
- logfp = stderr;
- }
- fputs(outbuf, logfp);
- fatal_error(outbuf);
- /* Never get here */
- break;
- }
- if (outc < BUFFER_SIZE-1)
- {
- strcpy(outbuf + oldoutc, tempbuf);
- }
- else
- {
- outbuf[oldoutc] = '\0';
- }
- break;
- case 'c':
- /*
- * Note that char paramaters are converted to int, so we need to
- * pass "int" to va_arg. (See K&R, 2nd ed, section A7.3.2, page 202)
- */
- outbuf[outc++] = (char) va_arg( ap, int );
- break;
- case 's':
- sval = va_arg( ap, char * );
- if (sval == NULL)
- {
- sval = "[null]";
- }
- oldoutc = outc;
- outc += strlen(sval);
- if (outc < BUFFER_SIZE-1)
- {
- strcpy(outbuf + oldoutc, sval);
- }
- else
- {
- outbuf[oldoutc] = '\0';
- }
- break;
- case 'N':
- /* Non-standard: Print a counted string. Takes 2 parameters:
- * int length, const char * string
- */
- ival = va_arg( ap, int );
- sval = va_arg( ap, char * );
- if (sval == NULL)
- {
- sval = "[null]";
- }
- if (ival < 0)
- {
- ival = 0;
- }
- oldoutc = outc;
- outc += ival;
- if (outc < BUFFER_SIZE-1)
- {
- memcpy(outbuf + oldoutc, sval, (size_t) ival);
- }
- else
- {
- outbuf[oldoutc] = '\0';
- }
- break;
- case 'E':
- /* Non-standard: Print error code from errno */
-#ifdef _WIN32
- ival = WSAGetLastError();
- sval = w32_socket_strerr(ival, tempbuf);
-#elif __OS2__
- ival = sock_errno();
- if (ival != 0)
- sval = os2_socket_strerr(ival, tempbuf);
- else
- {
- ival = errno;
- sval = strerror(ival);
- }
-#else /* ifndef _WIN32 */
- ival = errno;
-#ifdef HAVE_STRERROR
- sval = strerror(ival);
-#else /* ifndef HAVE_STRERROR */
- sval = NULL;
-#endif /* ndef HAVE_STRERROR */
- if (sval == NULL)
- {
- sprintf(tempbuf, "(errno = %d)", ival);
- sval = tempbuf;
- }
-#endif /* ndef _WIN32 */
- oldoutc = outc;
- outc += strlen(sval);
- if (outc < BUFFER_SIZE-1)
- {
- strcpy(outbuf + oldoutc, sval);
- }
- else
- {
- outbuf[oldoutc] = '\0';
- }
- break;
- case 'T':
- /* Non-standard: Print a Common Log File timestamp */
- {
- /*
- * Write timestamp into tempbuf.
- *
- * Complex because not all OSs have tm_gmtoff or
- * the %z field in strftime()
- */
- time_t now;
- struct tm *tm_now;
- struct tm gmt;
-#ifdef HAVE_LOCALTIME_R
- struct tm dummy;
-#endif
- int days, hrs, mins;
- time (&now);
-#ifdef HAVE_GMTIME_R
- gmt = *gmtime_r(&now, &gmt);
-#elif FEATURE_PTHREAD
- pthread_mutex_lock(&gmtime_mutex);
- gmt = *gmtime(&now);
- pthread_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);
- tm_now = localtime (&now);
- pthread_mutex_unlock(&localtime_mutex);
-#else
- tm_now = localtime (&now);
-#endif
- days = tm_now->tm_yday - gmt.tm_yday;
- hrs = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + tm_now->tm_hour - gmt.tm_hour);
- mins = hrs * 60 + tm_now->tm_min - gmt.tm_min;
- strftime (tempbuf, BUFFER_SIZE-6, "%d/%b/%Y:%H:%M:%S ", tm_now);
- sprintf (tempbuf + strlen(tempbuf), "%+03d%02d", mins / 60, abs(mins) % 60);
- }
- oldoutc = outc;
- outc += strlen(tempbuf);
- if (outc < BUFFER_SIZE-1)
- {
- strcpy(outbuf + oldoutc, tempbuf);
- }
- else
- {
- outbuf[oldoutc] = '\0';
- }
- break;
- default:
- sprintf(outbuf, "Privoxy(%08lx) Error: log_error(): Bad format string:\n"
- "Format = \"%s\"\n"
- "Exiting.", this_thread, fmt);
- if( !logfp )
- {
- logfp = stderr;
- }
- fputs(outbuf_save, logfp);
- unlock_logfile();
- fatal_error(outbuf_save);
- /* Never get here */
- break;
-
- } /* switch( p ) */
-
- } /* for( p ... ) */
-
- /* done with var. args */
- va_end( ap );
-
- if (outc >= BUFFER_SIZE-2)
- {
- /* insufficient room for newline and trailing null. */
-
- static const char warning[] = "... [too long, truncated]\n";
-
- if (outc < BUFFER_SIZE)
- {
- /* Need to add terminating null in this case. */
- outbuf[outc] = '\0';
- }
-
- /* Truncate output */
- outbuf[BUFFER_SIZE - sizeof(warning)] = '\0';
-
- /* Append warning */
- strcat(outbuf, warning);
- }
- else
- {
- /* Add terminating newline and null */
- outbuf[outc++] = '\n';
- outbuf[outc] = '\0';
- }
-
- /* deal with glibc stupidity - it won't let you initialize logfp */
- if( !logfp )
- {
- logfp = stderr;
- }
-
- fputs(outbuf_save, logfp);
-
- if (loglevel == LOG_LEVEL_FATAL)
- {
- fatal_error(outbuf_save);
- /* Never get here */
- }
-
- unlock_logfile();
-
-#if defined(_WIN32) && !defined(_WIN_CONSOLE)
- /* Write to display */
- LogPutString(outbuf_save);
-#endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
-
+ assert(0);
+ return "Internal error";
}
-#endif /* defined(USE_NEW_LOG_ERROR) */
-
#ifdef _WIN32
/*********************************************************************