-const char errlog_rcs[] = "$Id: errlog.c,v 1.54 2007/09/22 16:15:34 fabiankeil Exp $";
+const char errlog_rcs[] = "$Id: errlog.c,v 1.55 2007/10/14 14:12:41 fabiankeil Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/errlog.c,v $
*
* Revisions :
* $Log: errlog.c,v $
+ * 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.
#include "config.h"
#include "miscutil.h"
-#if defined(HAVE_STRLCPY) && defined(HAVE_GETTIMEOFDAY)
-#define USE_NEW_LOG_ERROR
/* For gettimeofday() */
#include <sys/time.h>
-#endif /* defined(HAVE_STRLCPY) && defined(HAVE_GETTIMEOFDAY) */
#if !defined(_WIN32) && !defined(__OS2__)
#include <unistd.h>
} /* 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.
- */
-
/*********************************************************************
*
* Function : get_thread_id
}
-#else /* use traditional log_error version */
-
-/*********************************************************************
- *
- * Function : log_error
- *
- * Description : This is the error-reporting and logging function.
- *
- * 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).
- *
- * Returns : N/A
- *
- *********************************************************************/
-void log_error(int loglevel, const char *fmt, ...)
-{
- 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)
- {
- 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;
- default:
- outc = sprintf(outbuf, "Privoxy(%08lx) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
- break;
- }
-
- /* 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) */
-
-}
-#endif /* defined(USE_NEW_LOG_ERROR) */
-
/*********************************************************************
*