Add /usr/xpg4/bin to the PATH to make sure the POSIX
[privoxy.git] / errlog.c
1 const char errlog_rcs[] = "$Id: errlog.c,v 1.50 2007/04/11 10:55:44 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/errlog.c,v $
5  *
6  * Purpose     :  Log errors to a designated destination in an elegant,
7  *                printf-like fashion.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001-2007 the SourceForge
10  *                Privoxy team. http://www.privoxy.org/
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and 
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it 
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  * Revisions   :
35  *    $Log: errlog.c,v $
36  *    Revision 1.50  2007/04/11 10:55:44  fabiankeil
37  *    Enforce some assertions that could be triggered
38  *    on mingw32 and other systems where we use threads
39  *    but no locks.
40  *
41  *    Revision 1.49  2007/04/08 16:44:15  fabiankeil
42  *    We need <sys/time.h> for gettimeofday(), not <time.h>.
43  *
44  *    Revision 1.48  2007/03/31 13:33:28  fabiankeil
45  *    Add alternative log_error() with timestamps
46  *    that contain milliseconds and without using
47  *    strcpy(), strcat() or sprintf().
48  *
49  *    Revision 1.47  2006/11/28 15:25:15  fabiankeil
50  *    Only unlink the pidfile if it's actually used.
51  *
52  *    Revision 1.46  2006/11/13 19:05:51  fabiankeil
53  *    Make pthread mutex locking more generic. Instead of
54  *    checking for OSX and OpenBSD, check for FEATURE_PTHREAD
55  *    and use mutex locking unless there is an _r function
56  *    available. Better safe than sorry.
57  *
58  *    Fixes "./configure --disable-pthread" and should result
59  *    in less threading-related problems on pthread-using platforms,
60  *    but it still doesn't fix BR#1122404.
61  *
62  *    Revision 1.45  2006/08/21 11:15:54  david__schmidt
63  *    MS Visual C++ build updates
64  *
65  *    Revision 1.44  2006/08/18 16:03:16  david__schmidt
66  *    Tweak for OS/2 build happiness.
67  *
68  *    Revision 1.43  2006/08/03 02:46:41  david__schmidt
69  *    Incorporate Fabian Keil's patch work:
70  *    http://www.fabiankeil.de/sourcecode/privoxy/
71  *
72  *    Revision 1.42  2006/07/18 14:48:46  david__schmidt
73  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
74  *    with what was really the latest development (the v_3_0_branch branch)
75  *
76  *    Revision 1.40.2.4  2005/04/03 20:10:50  david__schmidt
77  *    Thanks to Jindrich Makovicka for a race condition fix for the log
78  *    file.  The race condition remains for non-pthread implementations.
79  *    Reference patch #1175720.
80  *
81  *    Revision 1.40.2.3  2003/03/07 03:41:04  david__schmidt
82  *    Wrapping all *_r functions (the non-_r versions of them) with mutex 
83  *    semaphores for OSX.  Hopefully this will take care of all of those pesky
84  *    crash reports.
85  *
86  *    Revision 1.40.2.2  2002/09/28 00:30:57  david__schmidt
87  *    Update error logging to give sane values for thread IDs on Mach kernels.
88  *    It's still a hack, but at least it looks farily normal.  We print the
89  *    absolute value of the first 4 bytes of the pthread_t modded with 1000.
90  *
91  *    Revision 1.40.2.1  2002/09/25 12:47:42  oes
92  *    Make log_error safe against NULL string arguments
93  *
94  *    Revision 1.40  2002/05/22 01:27:27  david__schmidt
95  *
96  *    Add os2_socket_strerr mirroring w32_socket_strerr.
97  *
98  *    Revision 1.39  2002/04/03 17:15:27  gliptak
99  *    zero padding thread ids in log
100  *
101  *    Revision 1.38  2002/03/31 17:18:59  jongfoster
102  *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
103  *
104  *    Revision 1.37  2002/03/27 14:32:43  david__schmidt
105  *    More compiler warning message maintenance
106  *
107  *    Revision 1.36  2002/03/26 22:29:54  swa
108  *    we have a new homepage!
109  *
110  *    Revision 1.35  2002/03/24 15:23:33  jongfoster
111  *    Name changes
112  *
113  *    Revision 1.34  2002/03/24 13:25:43  swa
114  *    name change related issues
115  *
116  *    Revision 1.33  2002/03/13 00:27:04  jongfoster
117  *    Killing warnings
118  *
119  *    Revision 1.32  2002/03/07 03:46:17  oes
120  *    Fixed compiler warnings
121  *
122  *    Revision 1.31  2002/03/06 23:02:57  jongfoster
123  *    Removing tabs
124  *
125  *    Revision 1.30  2002/03/05 22:43:45  david__schmidt
126  *    - Better error reporting on OS/2
127  *    - Fix double-slash comment (oops)
128  *
129  *    Revision 1.29  2002/03/04 23:45:13  jongfoster
130  *    Printing thread ID if using Win32 native threads
131  *
132  *    Revision 1.28  2002/03/04 17:59:59  oes
133  *    Deleted deletePidFile(), cosmetics
134  *
135  *    Revision 1.27  2002/03/04 02:08:01  david__schmidt
136  *    Enable web editing of actions file on OS/2 (it had been broken all this time!)
137  *
138  *    Revision 1.26  2002/01/09 19:05:45  steudten
139  *    Fix big memory leak.
140  *
141  *    Revision 1.25  2002/01/09 14:32:08  oes
142  *    Added support for gmtime_r and localtime_r.
143  *
144  *    Revision 1.24  2001/12/30 14:07:32  steudten
145  *    - Add signal handling (unix)
146  *    - Add SIGHUP handler (unix)
147  *    - Add creation of pidfile (unix)
148  *    - Add action 'top' in rc file (RH)
149  *    - Add entry 'SIGNALS' to manpage
150  *    - Add exit message to logfile (unix)
151  *
152  *    Revision 1.23  2001/11/07 00:02:13  steudten
153  *    Add line number in error output for lineparsing for
154  *    actionsfile and configfile.
155  *    Special handling for CLF added.
156  *
157  *    Revision 1.22  2001/11/05 23:43:05  steudten
158  *    Add time+date to log files.
159  *
160  *    Revision 1.21  2001/10/25 03:40:47  david__schmidt
161  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
162  *    threads to call select() simultaneously.  So, it's time to do a real, live,
163  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
164  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
165  *
166  *    Revision 1.20  2001/09/16 23:04:34  jongfoster
167  *    Fixing a warning
168  *
169  *    Revision 1.19  2001/09/13 20:08:06  jongfoster
170  *    Adding support for LOG_LEVEL_CGI
171  *
172  *    Revision 1.18  2001/09/10 11:27:24  oes
173  *    Declaration of w32_socket_strerr now conditional
174  *
175  *    Revision 1.17  2001/09/10 10:17:13  oes
176  *    Removed unused variable; Fixed sprintf format
177  *
178  *    Revision 1.16  2001/07/30 22:08:36  jongfoster
179  *    Tidying up #defines:
180  *    - All feature #defines are now of the form FEATURE_xxx
181  *    - Permanently turned off WIN_GUI_EDIT
182  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
183  *
184  *    Revision 1.15  2001/07/29 17:41:10  jongfoster
185  *    Now prints thread ID for each message (pthreads only)
186  *
187  *    Revision 1.14  2001/07/19 19:03:48  haroon
188  *    - Added case for LOG_LEVEL_POPUPS
189  *
190  *    Revision 1.13  2001/07/13 13:58:58  oes
191  *     - Added case for LOG_LEVEL_DEANIMATE
192  *     - Removed all #ifdef PCRS
193  *
194  *    Revision 1.12  2001/06/09 10:55:28  jongfoster
195  *    Changing BUFSIZ ==> BUFFER_SIZE
196  *
197  *    Revision 1.11  2001/06/01 18:14:49  jongfoster
198  *    Changing the calls to strerr() to check HAVE_STRERR (which is defined
199  *    in config.h if appropriate) rather than the NO_STRERR macro.
200  *
201  *    Revision 1.10  2001/05/29 11:52:21  oes
202  *    Conditional compilation of w32_socket_error
203  *
204  *    Revision 1.9  2001/05/28 16:15:17  jongfoster
205  *    Improved reporting of errors under Win32.
206  *
207  *    Revision 1.8  2001/05/26 17:25:14  jongfoster
208  *    Added support for CLF (Common Log Format) and fixed LOG_LEVEL_LOG
209  *
210  *    Revision 1.7  2001/05/26 15:21:28  jongfoster
211  *    Activity animation in Win32 GUI now works even if debug==0
212  *
213  *    Revision 1.6  2001/05/25 21:55:08  jongfoster
214  *    Now cleans up properly on FATAL (removes taskbar icon etc)
215  *
216  *    Revision 1.5  2001/05/22 18:46:04  oes
217  *
218  *    - Enabled filtering banners by size rather than URL
219  *      by adding patterns that replace all standard banner
220  *      sizes with the "Junkbuster" gif to the re_filterfile
221  *
222  *    - Enabled filtering WebBugs by providing a pattern
223  *      which kills all 1x1 images
224  *
225  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
226  *      which is selected by the (nonstandard and therefore
227  *      capital) letter 'U' in the option string.
228  *      It causes the quantifiers to be ungreedy by default.
229  *      Appending a ? turns back to greedy (!).
230  *
231  *    - Added a new interceptor ijb-send-banner, which
232  *      sends back the "Junkbuster" gif. Without imagelist or
233  *      MSIE detection support, or if tinygif = 1, or the
234  *      URL isn't recognized as an imageurl, a lame HTML
235  *      explanation is sent instead.
236  *
237  *    - Added new feature, which permits blocking remote
238  *      script redirects and firing back a local redirect
239  *      to the browser.
240  *      The feature is conditionally compiled, i.e. it
241  *      can be disabled with --disable-fast-redirects,
242  *      plus it must be activated by a "fast-redirects"
243  *      line in the config file, has its own log level
244  *      and of course wants to be displayed by show-proxy-args
245  *      Note: Boy, all the #ifdefs in 1001 locations and
246  *      all the fumbling with configure.in and acconfig.h
247  *      were *way* more work than the feature itself :-(
248  *
249  *    - Because a generic redirect template was needed for
250  *      this, tinygif = 3 now uses the same.
251  *
252  *    - Moved GIFs, and other static HTTP response templates
253  *      to project.h
254  *
255  *    - Some minor fixes
256  *
257  *    - Removed some >400 CRs again (Jon, you really worked
258  *      a lot! ;-)
259  *
260  *    Revision 1.4  2001/05/21 19:32:54  jongfoster
261  *    Added another #ifdef _WIN_CONSOLE
262  *
263  *    Revision 1.3  2001/05/20 01:11:40  jongfoster
264  *    Added support for LOG_LEVEL_FATAL
265  *    Renamed LOG_LEVEL_FRC to LOG_LEVEL_FORCE,
266  *    and LOG_LEVEL_REF to LOG_LEVEL_RE_FILTER
267  *
268  *    Revision 1.2  2001/05/17 22:42:01  oes
269  *     - Cleaned CRLF's from the sources and related files
270  *     - Repaired logging for REF and FRC
271  *
272  *    Revision 1.1.1.1  2001/05/15 13:58:51  oes
273  *    Initial import of version 2.9.3 source tree
274  *
275  *
276  *********************************************************************/
277 \f
278
279 #include "config.h"
280 #include "miscutil.h"
281
282 #include <stdlib.h>
283 #include <stdio.h>
284 #include <stdarg.h>
285 #include <string.h>
286
287 #if defined(HAVE_STRLCPY) && defined(HAVE_GETTIMEOFDAY)
288 #define USE_NEW_LOG_ERROR
289 /* For gettimeofday() */
290 #include <sys/time.h>
291 #endif /* defined(HAVE_STRLCPY) && defined(HAVE_GETTIMEOFDAY) */
292
293 #if !defined(_WIN32) && !defined(__OS2__)
294 #include <unistd.h>
295 #endif /* !defined(_WIN32) && !defined(__OS2__) */
296
297 #include <errno.h>
298 #include <assert.h>
299
300 #ifdef _WIN32
301 #ifndef STRICT
302 #define STRICT
303 #endif
304 #include <windows.h>
305 #ifndef _WIN_CONSOLE
306 #include "w32log.h"
307 #endif /* ndef _WIN_CONSOLE */
308 #endif /* def _WIN32 */
309 #ifdef _MSC_VER
310 #define inline __inline
311 #endif /* def _MSC_VER */
312
313 #ifdef __OS2__
314 #include <sys/socket.h> /* For sock_errno */
315 #define INCL_DOS
316 #include <os2.h>
317 #endif
318
319 #include "errlog.h"
320 #include "project.h"
321 #include "jcc.h"
322
323 const char errlog_h_rcs[] = ERRLOG_H_VERSION;
324
325
326 /*
327  * LOG_LEVEL_FATAL cannot be turned off.  (There are
328  * some exceptional situations where we need to get a
329  * message to the user).
330  */
331 #define LOG_LEVEL_MINIMUM  LOG_LEVEL_FATAL
332
333 /* where to log (default: stderr) */
334 static FILE *logfp = NULL;
335
336 /* logging detail level.  */
337 int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR | LOG_LEVEL_INFO);  
338
339 /* static functions */
340 static void fatal_error(const char * error_message);
341 #ifdef _WIN32
342 static char *w32_socket_strerr(int errcode, char *tmp_buf);
343 #endif
344 #ifdef __OS2__
345 static char *os2_socket_strerr(int errcode, char *tmp_buf);
346 #endif
347
348 #ifdef FEATURE_PTHREAD
349 static inline void lock_logfile()
350 {
351    pthread_mutex_lock(&log_mutex);
352 }
353 static inline void unlock_logfile()
354 {
355    pthread_mutex_unlock(&log_mutex);
356 }
357 static inline void lock_loginit()
358 {
359    pthread_mutex_lock(&log_init_mutex);
360 }
361 static inline void unlock_loginit()
362 {
363    pthread_mutex_unlock(&log_init_mutex);
364 }
365 #else /* ! FEATURE_PTHREAD */
366 /*
367  * FIXME we need a cross-platform locking mechanism.
368  * The locking/unlocking functions below should be 
369  * fleshed out for non-pthread implementations.
370  */ 
371 static inline void lock_logfile() {}
372 static inline void unlock_logfile() {}
373 static inline void lock_loginit() {}
374 static inline void unlock_loginit() {}
375 #endif
376
377 /*********************************************************************
378  *
379  * Function    :  fatal_error
380  *
381  * Description :  Displays a fatal error to standard error (or, on 
382  *                a WIN32 GUI, to a dialog box), and exits
383  *                JunkBuster with status code 1.
384  *
385  * Parameters  :
386  *          1  :  error_message = The error message to display.
387  *
388  * Returns     :  Does not return.
389  *
390  *********************************************************************/
391 static void fatal_error(const char * error_message)
392 {
393 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
394    MessageBox(g_hwndLogFrame, error_message, "Privoxy Error", 
395       MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
396
397    /* Cleanup - remove taskbar icon etc. */
398    TermLogWindow();
399
400 #else /* if !defined(_WIN32) || defined(_WIN_CONSOLE) */
401    fputs(error_message, stderr);
402 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
403
404 #if defined(unix)
405    if(pidfile)
406    {
407       unlink(pidfile);
408    }
409 #endif /* unix */
410
411    exit(1);
412 }
413
414
415 /*********************************************************************
416  *
417  * Function    :  init_error_log
418  *
419  * Description :  Initializes the logging module.  Must call before
420  *                calling log_error.
421  *
422  * Parameters  :
423  *          1  :  prog_name  = The program name.
424  *          2  :  logfname   = The logfile name, or NULL for stderr.
425  *          3  :  debuglevel = The debugging level.
426  *
427  * Returns     :  N/A
428  *
429  *********************************************************************/
430 void init_error_log(const char *prog_name, const char *logfname, int debuglevel)
431 {
432    FILE *fp;
433
434    lock_loginit();
435
436    /* set the logging detail level */
437    debug = debuglevel | LOG_LEVEL_MINIMUM;
438
439    if ((logfp != NULL) && (logfp != stderr))
440    {
441       log_error(LOG_LEVEL_INFO, "(Re-)Open logfile %s", logfname ? logfname : "none");
442       lock_logfile();
443       fclose(logfp);
444    } else {
445       lock_logfile();
446    }
447    logfp = stderr;
448    unlock_logfile();
449
450    /* set the designated log file */
451    if( logfname )
452    {
453       if( NULL == (fp = fopen(logfname, "a")) )
454       {
455          log_error(LOG_LEVEL_FATAL, "init_error_log(): can't open logfile: %s", logfname);
456       }
457
458       /* set logging to be completely unbuffered */
459       setbuf(fp, NULL);
460
461       lock_logfile();
462       logfp = fp;
463       unlock_logfile();
464    }
465
466    log_error(LOG_LEVEL_INFO, "Privoxy version " VERSION);
467    if (prog_name != NULL)
468    {
469       log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
470    }
471
472    unlock_loginit();
473
474 } /* init_error_log */
475
476 #if defined(USE_NEW_LOG_ERROR)
477 /*
478  * Use an alternative log_error version and its helper functions.
479  *
480  * The code is mostly copied from the old log_error
481  * function but it's divided into multiple functions,
482  * doesn't use strcpy, strcat or sprintf and compiles
483  * with gcc43 without warnings (on FreeBSD that is).
484  *
485  * It should behave like the old log_error function with
486  * two exceptions:
487  *
488  * - too long format strings are logged truncated instead
489  *   of completely replaced with the truncation warning,
490  * - its time stamps contain milliseconds.
491  */
492
493 /*********************************************************************
494  *
495  * Function    :  get_thread_id
496  *
497  * Description :  Returns a number that is different for each thread.
498  *
499  *                XXX: Should be moved elsewhere (miscutil.c?)
500  *                
501  * Parameters  :  None
502  *
503  * Returns     :  thread_id
504  *
505  *********************************************************************/
506 long get_thread_id(void)
507 {
508    long this_thread = 1;  /* was: pthread_t this_thread;*/
509
510 #ifdef __OS2__
511    PTIB     ptib;
512    APIRET   ulrc; /* XXX: I have no clue what this does */
513 #endif /* __OS2__ */
514
515    /* FIXME get current thread id */
516 #ifdef FEATURE_PTHREAD
517    this_thread = (long)pthread_self();
518 #ifdef __MACH__
519    /*
520     * Mac OSX (and perhaps other Mach instances) doesn't have a debuggable
521     * value at the first 4 bytes of pthread_self()'s return value, a pthread_t.
522     * pthread_t is supposed to be opaque... but it's fairly random, though, so
523     * we make it mostly presentable.
524     */
525    this_thread = abs(this_thread % 1000);
526 #endif /* def __MACH__ */
527 #elif defined(_WIN32)
528    this_thread = GetCurrentThreadId();
529 #elif defined(__OS2__)
530    ulrc = DosGetInfoBlocks(&ptib, NULL);
531    if (ulrc == 0)
532      this_thread = ptib -> tib_ptib2 -> tib2_ultid;
533 #endif /* def FEATURE_PTHREAD */
534
535    return this_thread;
536 }
537
538
539 /*********************************************************************
540  *
541  * Function    :  get_log_timestamp
542  *
543  * Description :  Generates the time stamp for the log message prefix.
544  *
545  * Parameters  :
546  *          1  :  buffer = Storage buffer
547  *          2  :  buffer_size = Size of storage buffer
548  *
549  * Returns     :  Number of written characters or 0 for error.
550  *
551  *********************************************************************/
552 static inline size_t get_log_timestamp(char *buffer, size_t buffer_size)
553 {
554    size_t length;
555    time_t now; 
556    struct tm tm_now;
557    struct timeval tv_now; /* XXX: stupid name */
558    gettimeofday(&tv_now, NULL);
559    long msecs = tv_now.tv_usec / 1000;
560    int msecs_length = 0;
561
562    time(&now);
563
564 #ifdef HAVE_LOCALTIME_R
565    tm_now = *localtime_r(&now, &tm_now);
566 #elif FEATURE_PTHREAD
567    pthread_mutex_lock(&localtime_mutex);
568    tm_now = *localtime(&now); 
569    pthread_mutex_unlock(&localtime_mutex);
570 #else
571    tm_now = *localtime(&now); 
572 #endif
573
574    length = strftime(buffer, buffer_size, "%b %d %H:%M:%S", &tm_now);
575    if (length > 0);
576    {
577       msecs_length = snprintf(buffer+length, buffer_size - length, ".%.3ld", msecs);               
578    }
579    if (msecs_length > 0)
580    {
581       length += (size_t)msecs_length;
582    }
583    else
584    {
585       length = 0;
586    }
587
588    return length;
589 }
590
591
592 /*********************************************************************
593  *
594  * Function    :  get_clf_timestamp
595  *
596  * Description :  Generates a Common Log Format time string.
597  *
598  * Parameters  :
599  *          1  :  buffer = Storage buffer
600  *          2  :  buffer_size = Size of storage buffer
601  *
602  * Returns     :  Number of written characters or 0 for error.
603  *
604  *********************************************************************/
605 static inline size_t get_clf_timestamp(char *buffer, size_t buffer_size)
606 {
607    /*
608     * Complex because not all OSs have tm_gmtoff or
609     * the %z field in strftime()
610     */
611    time_t now;
612    struct tm *tm_now; 
613    struct tm gmt;
614 #ifdef HAVE_LOCALTIME_R
615    struct tm dummy;
616 #endif
617    int days, hrs, mins;
618    size_t length;
619    int tz_length = 0;
620
621    time (&now); 
622 #ifdef HAVE_GMTIME_R
623    gmt = *gmtime_r(&now, &gmt);
624 #elif FEATURE_PTHREAD
625    pthread_mutex_lock(&gmtime_mutex);
626    gmt = *gmtime(&now);
627    pthread_mutex_unlock(&gmtime_mutex);
628 #else
629    gmt = *gmtime(&now);
630 #endif
631 #ifdef HAVE_LOCALTIME_R
632    tm_now = localtime_r(&now, &dummy);
633 #elif FEATURE_PTHREAD
634    pthread_mutex_lock(&localtime_mutex);
635    tm_now = localtime(&now); 
636    pthread_mutex_unlock(&localtime_mutex);
637 #else
638    tm_now = localtime(&now); 
639 #endif
640    days = tm_now->tm_yday - gmt.tm_yday; 
641    hrs = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + tm_now->tm_hour - gmt.tm_hour); 
642    mins = hrs * 60 + tm_now->tm_min - gmt.tm_min; 
643
644    length = strftime(buffer, buffer_size, "%d/%b/%Y:%H:%M:%S ", tm_now);
645
646    if (length > 0);
647    {
648       tz_length = snprintf(buffer+length, buffer_size-length,
649                      "%+03d%02d", mins / 60, abs(mins) % 60);
650    }
651    if (tz_length > 0)
652    {
653       length += (size_t)tz_length;
654    }
655    else
656    {
657       length = 0;
658    }
659
660    return length;
661 }
662
663
664 /*********************************************************************
665  *
666  * Function    :  get_log_level_string
667  *
668  * Description :  Translates a numerical loglevel into a string.
669  *
670  * Parameters  :  
671  *          1  :  loglevel = LOG_LEVEL_FOO
672  *
673  * Returns     :  Log level string.
674  *
675  *********************************************************************/
676 inline const char *get_log_level_string(int loglevel)
677 {
678    char *log_level_string = NULL;
679
680    assert(0 < loglevel);
681
682    switch (loglevel)
683    {
684       case LOG_LEVEL_ERROR:
685          log_level_string = "Error";
686          break;
687       case LOG_LEVEL_FATAL:
688          log_level_string = "Fatal error";
689          break;
690       case LOG_LEVEL_GPC:
691          log_level_string = "Request";
692          break;
693       case LOG_LEVEL_CONNECT:
694          log_level_string = "Connect";
695          break;
696       case LOG_LEVEL_LOG:
697          log_level_string = "Writing";
698          break;
699       case LOG_LEVEL_HEADER:
700          log_level_string = "Header";
701          break;
702       case LOG_LEVEL_INFO:
703          log_level_string = "Info";
704          break;
705       case LOG_LEVEL_RE_FILTER:
706          log_level_string = "Re-Filter";
707          break;
708 #ifdef FEATURE_FORCE_LOAD
709       case LOG_LEVEL_FORCE:
710          log_level_string = "Force";
711          break;
712 #endif /* def FEATURE_FORCE_LOAD */
713 #ifdef FEATURE_FAST_REDIRECTS
714       case LOG_LEVEL_REDIRECTS:
715          log_level_string = "Redirect";
716          break;
717 #endif /* def FEATURE_FAST_REDIRECTS */
718       case LOG_LEVEL_DEANIMATE:
719          log_level_string = "Gif-Deanimate";
720          break;
721 #ifdef FEATURE_KILL_POPUPS
722       case LOG_LEVEL_POPUPS:
723          log_level_string = "Kill-Popups";
724          break;
725 #endif /* def FEATURE_KILL_POPUPS */
726       case LOG_LEVEL_CGI:
727          log_level_string = "CGI";
728          break;
729       default:
730          log_level_string = "Unknown log level";
731          break;
732    }
733    assert(NULL != log_level_string);
734
735    return log_level_string;
736 }
737
738
739 /*********************************************************************
740  *
741  * Function    :  log_error
742  *
743  * Description :  This is the error-reporting and logging function.
744  *
745  * Parameters  :
746  *          1  :  loglevel  = the type of message to be logged
747  *          2  :  fmt       = the main string we want logged, printf-like
748  *          3  :  ...       = arguments to be inserted in fmt (printf-like).
749  *
750  * Returns     :  N/A
751  *
752  *********************************************************************/
753 void log_error(int loglevel, const char *fmt, ...)
754 {
755    va_list ap;
756    char *outbuf = NULL;
757    static char *outbuf_save = NULL;
758    char tempbuf[BUFFER_SIZE];
759    size_t length = 0;
760    const char * src = fmt;
761    long thread_id;
762    char timestamp[30];
763    /*
764     * XXX: Make this a config option,
765     * why else do we allocate instead of using
766     * an array?
767     */
768    size_t log_buffer_size = BUFFER_SIZE;
769
770 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
771    /*
772     * Irrespective of debug setting, a GET/POST/CONNECT makes
773     * the taskbar icon animate.  (There is an option to disable
774     * this but checking that is handled inside LogShowActivity()).
775     */
776    if (loglevel == LOG_LEVEL_GPC)
777    {
778       LogShowActivity();
779    }
780 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
781
782    /* verify if loglevel applies to current settings and bail out if negative */
783    if ((loglevel & debug) == 0)
784    {
785       return;
786    }
787
788    thread_id = get_thread_id();
789    get_log_timestamp(timestamp, sizeof(timestamp));
790
791    /* protect the whole function because of the static buffer (outbuf) */
792    lock_logfile();
793
794    if (NULL == outbuf_save) 
795    {
796       outbuf_save = (char*)zalloc(log_buffer_size + 1); /* +1 for paranoia */
797       if (NULL == outbuf_save)
798       {
799          snprintf(tempbuf, sizeof(tempbuf),
800             "%s Privoxy(%08lx) Fatal error: log_error() failed to allocate buffer memory.\n"
801             "\nExiting.", timestamp, thread_id);
802          if( !logfp )
803          {
804             logfp = stderr;
805          }
806          fputs(tempbuf, logfp);
807          unlock_logfile();
808          fatal_error(tempbuf); /* Exit */
809       }
810    }
811    outbuf = outbuf_save;
812
813    /*
814     * Memsetting the whole buffer to zero (in theory)
815     * makes things easier later on.
816     */
817    memset(outbuf, 0, log_buffer_size);
818
819    /* Add prefix for everything but Common Log Format messages */
820    if (loglevel != LOG_LEVEL_CLF)
821    {
822       length = (size_t)snprintf(outbuf, log_buffer_size, "%s Privoxy(%08lx) %s: ",
823                                 timestamp, thread_id, get_log_level_string(loglevel));
824    }
825
826    /* get ready to scan var. args. */
827    va_start(ap, fmt);
828
829    /* build formatted message from fmt and var-args */
830    while ((*src) && (length < log_buffer_size-2))
831    {
832       const char *sval = NULL; /* %N string  */
833       int ival;                /* %N string length or an error code */
834       unsigned uval;           /* %u value */
835       long lval;               /* %l value */
836       unsigned long ulval;     /* %ul value */
837       char ch;
838       const char *format_string = tempbuf;
839
840       ch = *src++;
841       if (ch != '%')
842       {
843          outbuf[length++] = ch;
844          /*
845           * XXX: Only necessary on platforms which don't use pthread
846           * mutexes (mingw32 for example), where multiple threads can
847           * write to the buffer at the same time.
848           */
849          outbuf[length] = '\0';
850          continue;
851       }
852       outbuf[length] = '\0';
853       ch = *src++;
854       switch (ch) {
855          case '%':
856             tempbuf[0] = '%';
857             tempbuf[1] = '\0';
858             break;
859          case 'd':
860             ival = va_arg( ap, int );
861             snprintf(tempbuf, sizeof(tempbuf), "%d", ival);
862             break;
863          case 'u':
864             uval = va_arg( ap, unsigned );
865             snprintf(tempbuf, sizeof(tempbuf), "%u", uval);
866             break;
867          case 'l':
868             /* this is a modifier that must be followed by u or d */
869             ch = *src++;
870             if (ch == 'd')
871             {
872                lval = va_arg( ap, long );
873                snprintf(tempbuf, sizeof(tempbuf), "%ld", lval);
874             }
875             else if (ch == 'u')
876             {
877                ulval = va_arg( ap, unsigned long );
878                snprintf(tempbuf, sizeof(tempbuf), "%lu", ulval);
879             }
880             else
881             {
882                snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt);
883                loglevel = LOG_LEVEL_FATAL;
884             }
885             break;
886          case 'c':
887             /*
888              * Note that char paramaters are converted to int, so we need to
889              * pass "int" to va_arg.  (See K&R, 2nd ed, section A7.3.2, page 202)
890              */
891             tempbuf[0] = (char) va_arg(ap, int);
892             tempbuf[1] = '\0';
893             break;
894          case 's':
895             format_string = va_arg(ap, char *);
896             if (format_string == NULL)
897             {
898                format_string = "[null]";
899             }
900             break;
901          case 'N':
902             /*
903              * Non-standard: Print a counted unterminated string.
904              * Takes 2 parameters: int length, const char * string.
905              */
906             ival = va_arg(ap, int);
907             sval = va_arg(ap, char *);
908             if (sval == NULL)
909             {
910                format_string = "[null]";
911             }
912             else if (ival <= 0)
913             {
914                if (0 == ival)
915                {
916                   /* That's ok (but stupid) */
917                   tempbuf[0] = '\0';
918                }
919                else
920                {
921                   /*
922                    * That's not ok (and even more stupid)
923                    */
924                   assert(ival >= 0);
925                   format_string = "[counted string lenght < 0]";
926                }
927             }
928             else if (ival >= sizeof(tempbuf))
929             {
930                /*
931                 * String is too long, copy as much as possible.
932                 * It will be further truncated later.
933                 */
934                memcpy(tempbuf, sval, sizeof(tempbuf)-1);
935                tempbuf[sizeof(tempbuf)-1] = '\0';
936             }
937             else
938             {
939                memcpy(tempbuf, sval, (size_t) ival);
940                tempbuf[ival] = '\0';
941             }
942             break;
943          case 'E':
944             /* Non-standard: Print error code from errno */
945 #ifdef _WIN32
946             ival = WSAGetLastError();
947             format_string = w32_socket_strerr(ival, tempbuf);
948 #elif __OS2__
949             ival = sock_errno();
950             if (ival != 0)
951             {
952                format_string = os2_socket_strerr(ival, tempbuf);
953             }
954             else
955             {
956                ival = errno;
957                format_string = strerror(ival);
958             }
959 #else /* ifndef _WIN32 */
960             ival = errno; 
961 #ifdef HAVE_STRERROR
962             format_string = strerror(ival);
963 #else /* ifndef HAVE_STRERROR */
964             format_string = NULL;
965 #endif /* ndef HAVE_STRERROR */
966             if (sval == NULL)
967             {
968                snprintf(tempbuf, sizeof(tempbuf), "(errno = %d)", ival);
969             }
970 #endif /* ndef _WIN32 */
971             break;
972          case 'T':
973             /* Non-standard: Print a Common Log File timestamp */
974             get_clf_timestamp(tempbuf, sizeof(tempbuf));
975             break;
976          default:
977             snprintf(tempbuf, sizeof(tempbuf), "Bad format string: \"%s\"", fmt);
978             loglevel = LOG_LEVEL_FATAL;
979             break;
980       } /* switch( p ) */
981
982       assert(length < log_buffer_size);
983       length += strlcpy(outbuf + length, format_string, log_buffer_size - length);
984
985       if (length >= log_buffer_size-2)
986       {
987          static char warning[] = "... [too long, truncated]";
988
989          length = log_buffer_size - sizeof(warning) - 1;
990          length += strlcpy(outbuf + length, warning, log_buffer_size - length);
991          assert(length < log_buffer_size);
992
993          break;
994       }
995    } /* for( p ... ) */
996
997    /* done with var. args */
998    va_end(ap);
999
1000    assert(length < log_buffer_size);
1001    length += strlcpy(outbuf + length, "\n", log_buffer_size - length);
1002
1003    /* Some sanity checks */
1004    if (!(length < log_buffer_size)
1005     || !(outbuf[log_buffer_size-1] == '\0')
1006     || !(outbuf[log_buffer_size] == '\0')
1007       )
1008    {
1009       /* Repeat as assertions */
1010       assert(length < log_buffer_size);
1011       assert(outbuf[log_buffer_size-1] == '\0');
1012       /*
1013        * outbuf's real size is log_buffer_size+1,
1014        * so while this looks like an off-by-one,
1015        * we're only checking our paranoia byte.
1016        */
1017       assert(outbuf[log_buffer_size] == '\0');
1018
1019       snprintf(outbuf, log_buffer_size,
1020          "%s Privoxy(%08lx) Fatal error: log_error()'s sanity checks failed. length: %d\n"
1021          "Exiting.", timestamp, thread_id, (int)length);
1022       loglevel = LOG_LEVEL_FATAL;
1023    }
1024
1025    /* deal with glibc stupidity - it won't let you initialize logfp */
1026    /* XXX: Still necessary? */
1027    if(NULL == logfp)
1028    {
1029       logfp = stderr;
1030    }
1031
1032    fputs(outbuf_save, logfp);
1033
1034    if (loglevel == LOG_LEVEL_FATAL)
1035    {
1036       fatal_error(outbuf_save);
1037       /* Never get here */
1038    }
1039
1040    unlock_logfile();
1041
1042 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
1043    /* Write to display */
1044    LogPutString(outbuf_save);
1045 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
1046
1047 }
1048
1049 #else /* use traditional log_error version */
1050
1051 /*********************************************************************
1052  *
1053  * Function    :  log_error
1054  *
1055  * Description :  This is the error-reporting and logging function.
1056  *
1057  * Parameters  :
1058  *          1  :  loglevel  = the type of message to be logged
1059  *          2  :  fmt       = the main string we want logged, printf-like
1060  *          3  :  ...       = arguments to be inserted in fmt (printf-like).
1061  *
1062  * Returns     :  N/A
1063  *
1064  *********************************************************************/
1065 void log_error(int loglevel, const char *fmt, ...)
1066 {
1067    va_list ap;
1068    char *outbuf= NULL;
1069    static char *outbuf_save = NULL;
1070    const char * src = fmt;
1071    int outc = 0;
1072    long this_thread = 1;  /* was: pthread_t this_thread;*/
1073 #ifdef __OS2__
1074    PTIB     ptib;
1075    APIRET   ulrc;
1076 #endif /* __OS2__ */
1077
1078 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
1079    /*
1080     * Irrespective of debug setting, a GET/POST/CONNECT makes
1081     * the taskbar icon animate.  (There is an option to disable
1082     * this but checking that is handled inside LogShowActivity()).
1083     */
1084    if (loglevel == LOG_LEVEL_GPC)
1085    {
1086       LogShowActivity();
1087    }
1088 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
1089
1090    /* verify if loglevel applies to current settings and bail out if negative */
1091    if ((loglevel & debug) == 0)
1092    {
1093       return;
1094    }
1095
1096    /* protect the whole function because of the static buffer (outbuf) */
1097    lock_logfile();
1098
1099    /* FIXME get current thread id */
1100 #ifdef FEATURE_PTHREAD
1101    this_thread = (long)pthread_self();
1102 #ifdef __MACH__
1103    /*
1104     * Mac OSX (and perhaps other Mach instances) doesn't have a debuggable
1105     * value at the first 4 bytes of pthread_self()'s return value, a pthread_t.
1106     * pthread_t is supposed to be opaque... but it's fairly random, though, so
1107     * we make it mostly presentable.
1108     */
1109    this_thread = abs(this_thread % 1000);
1110 #endif /* def __MACH__ */
1111 #elif defined(_WIN32)
1112    this_thread = GetCurrentThreadId();
1113 #elif defined(__OS2__)
1114    ulrc = DosGetInfoBlocks(&ptib, NULL);
1115    if (ulrc == 0)
1116      this_thread = ptib -> tib_ptib2 -> tib2_ultid;
1117 #endif /* def FEATURE_PTHREAD */
1118
1119    if ( !outbuf_save ) 
1120    {
1121       outbuf_save = outbuf = (char*)malloc(BUFFER_SIZE);
1122       if (NULL == outbuf_save)
1123       {
1124          fatal_error("Privoxy failed to allocate log buffer.");
1125       }
1126    }
1127    outbuf = outbuf_save;
1128
1129     {
1130        /*
1131         * Write timestamp into tempbuf.
1132         *
1133         * Complex because not all OSs have tm_gmtoff or
1134         * the %z field in strftime()
1135         */
1136        time_t now; 
1137        struct tm tm_now; 
1138        time (&now);
1139 #ifdef HAVE_LOCALTIME_R
1140        tm_now = *localtime_r(&now, &tm_now);
1141 #elif FEATURE_PTHREAD
1142        pthread_mutex_lock(&localtime_mutex);
1143        tm_now = *localtime (&now); 
1144        pthread_mutex_unlock(&localtime_mutex);
1145 #else
1146        tm_now = *localtime (&now); 
1147 #endif
1148        strftime(outbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now); 
1149        outbuf += strlen( outbuf );
1150     }
1151    switch (loglevel)
1152    {
1153       case LOG_LEVEL_ERROR:
1154          outc = sprintf(outbuf, "Privoxy(%08lx) Error: ", this_thread);
1155          break;
1156       case LOG_LEVEL_FATAL:
1157          outc = sprintf(outbuf, "Privoxy(%08lx) Fatal error: ", this_thread);
1158          break;
1159       case LOG_LEVEL_GPC:
1160          outc = sprintf(outbuf, "Privoxy(%08lx) Request: ", this_thread);
1161          break;
1162       case LOG_LEVEL_CONNECT:
1163          outc = sprintf(outbuf, "Privoxy(%08lx) Connect: ", this_thread);
1164          break;
1165       case LOG_LEVEL_LOG:
1166          outc = sprintf(outbuf, "Privoxy(%08lx) Writing: ", this_thread);
1167          break;
1168       case LOG_LEVEL_HEADER:
1169          outc = sprintf(outbuf, "Privoxy(%08lx) Header: ", this_thread);
1170          break;
1171       case LOG_LEVEL_INFO:
1172          outc = sprintf(outbuf, "Privoxy(%08lx) Info: ", this_thread);
1173          break;
1174       case LOG_LEVEL_RE_FILTER:
1175          outc = sprintf(outbuf, "Privoxy(%08lx) Re-Filter: ", this_thread);
1176          break;
1177 #ifdef FEATURE_FORCE_LOAD
1178       case LOG_LEVEL_FORCE:
1179          outc = sprintf(outbuf, "Privoxy(%08lx) Force: ", this_thread);
1180          break;
1181 #endif /* def FEATURE_FORCE_LOAD */
1182 #ifdef FEATURE_FAST_REDIRECTS
1183       case LOG_LEVEL_REDIRECTS:
1184          outc = sprintf(outbuf, "Privoxy(%08lx) Redirect: ", this_thread);
1185          break;
1186 #endif /* def FEATURE_FAST_REDIRECTS */
1187       case LOG_LEVEL_DEANIMATE:
1188          outc = sprintf(outbuf, "Privoxy(%08lx) Gif-Deanimate: ", this_thread);
1189          break;
1190       case LOG_LEVEL_CLF:
1191          outbuf = outbuf_save;
1192          outc = 0;
1193          outbuf[0] = '\0';
1194          break;
1195 #ifdef FEATURE_KILL_POPUPS
1196       case LOG_LEVEL_POPUPS:
1197          outc = sprintf(outbuf, "Privoxy(%08lx) Kill-Popups: ", this_thread);
1198          break;
1199 #endif /* def FEATURE_KILL_POPUPS */
1200       case LOG_LEVEL_CGI:
1201          outc = sprintf(outbuf, "Privoxy(%08lx) CGI: ", this_thread);
1202          break;
1203       default:
1204          outc = sprintf(outbuf, "Privoxy(%08lx) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
1205          break;
1206    }
1207    
1208    /* get ready to scan var. args. */
1209    va_start( ap, fmt );
1210
1211    /* build formatted message from fmt and var-args */
1212    while ((*src) && (outc < BUFFER_SIZE-2))
1213    {
1214       char tempbuf[BUFFER_SIZE];
1215       char *sval = NULL;
1216       int ival;
1217       unsigned uval;
1218       long lval;
1219       unsigned long ulval;
1220       int oldoutc;
1221       char ch;
1222       
1223       ch = *src++;
1224       if( ch != '%' )
1225       {
1226          outbuf[outc++] = ch;
1227          continue;
1228       }
1229
1230       ch = *src++;
1231       switch (ch) {
1232          case '%':
1233             outbuf[outc++] = '%';
1234             break;
1235          case 'd':
1236             ival = va_arg( ap, int );
1237             oldoutc = outc;
1238             outc += sprintf(tempbuf, "%d", ival);
1239             if (outc < BUFFER_SIZE-1) 
1240             {
1241                strcpy(outbuf + oldoutc, tempbuf);
1242             }
1243             else
1244             {
1245                outbuf[oldoutc] = '\0';
1246             }
1247             break;
1248          case 'u':
1249             uval = va_arg( ap, unsigned );
1250             oldoutc = outc;
1251             outc += sprintf(tempbuf, "%u", uval);
1252             if (outc < BUFFER_SIZE-1) 
1253             {
1254                strcpy(outbuf + oldoutc, tempbuf);
1255             }
1256             else
1257             {
1258                outbuf[oldoutc] = '\0';
1259             }
1260             break;
1261          case 'l':
1262             /* this is a modifier that must be followed by u or d */
1263             ch = *src++;
1264             if (ch == 'd')
1265             {
1266                lval = va_arg( ap, long );
1267                oldoutc = outc;
1268                outc += sprintf(tempbuf, "%ld", lval);
1269             }
1270             else if (ch == 'u')
1271             {
1272                ulval = va_arg( ap, unsigned long );
1273                oldoutc = outc;
1274                outc += sprintf(tempbuf, "%lu", ulval);
1275             }
1276             else
1277             {
1278                /* Error */
1279                sprintf(outbuf, "Privoxy(%08lx) Error: log_error(): Bad format string:\n"
1280                                "Format = \"%s\"\n"
1281                                "Exiting.", this_thread, fmt);
1282                if( !logfp )
1283                {
1284                   logfp = stderr;
1285                }
1286                fputs(outbuf, logfp);
1287                fatal_error(outbuf);
1288                /* Never get here */
1289                break;
1290             }
1291             if (outc < BUFFER_SIZE-1) 
1292             {
1293                strcpy(outbuf + oldoutc, tempbuf);
1294             }
1295             else
1296             {
1297                outbuf[oldoutc] = '\0';
1298             }
1299             break;
1300          case 'c':
1301             /*
1302              * Note that char paramaters are converted to int, so we need to
1303              * pass "int" to va_arg.  (See K&R, 2nd ed, section A7.3.2, page 202)
1304              */
1305             outbuf[outc++] = (char) va_arg( ap, int );
1306             break;
1307          case 's':
1308             sval = va_arg( ap, char * );
1309             if (sval == NULL)
1310             {
1311                sval = "[null]";
1312             }
1313             oldoutc = outc;
1314             outc += strlen(sval);
1315             if (outc < BUFFER_SIZE-1) 
1316             {
1317                strcpy(outbuf + oldoutc, sval);
1318             }
1319             else
1320             {
1321                outbuf[oldoutc] = '\0';
1322             }
1323             break;
1324          case 'N':
1325             /* Non-standard: Print a counted string.  Takes 2 parameters:
1326              * int length, const char * string
1327              */
1328             ival = va_arg( ap, int );
1329             sval = va_arg( ap, char * );
1330             if (sval == NULL)
1331             {
1332                sval = "[null]";
1333             }
1334             if (ival < 0)
1335             {
1336                ival = 0;
1337             }
1338             oldoutc = outc;
1339             outc += ival;
1340             if (outc < BUFFER_SIZE-1)
1341             {
1342                memcpy(outbuf + oldoutc, sval, (size_t) ival);
1343             }
1344             else
1345             {
1346                outbuf[oldoutc] = '\0';
1347             }
1348             break;
1349          case 'E':
1350             /* Non-standard: Print error code from errno */
1351 #ifdef _WIN32
1352             ival = WSAGetLastError();
1353             sval = w32_socket_strerr(ival, tempbuf);
1354 #elif __OS2__
1355             ival = sock_errno();
1356             if (ival != 0)
1357               sval = os2_socket_strerr(ival, tempbuf);
1358             else
1359             {
1360               ival = errno;
1361               sval = strerror(ival);
1362             }
1363 #else /* ifndef _WIN32 */
1364             ival = errno; 
1365 #ifdef HAVE_STRERROR
1366             sval = strerror(ival);
1367 #else /* ifndef HAVE_STRERROR */
1368             sval = NULL;
1369 #endif /* ndef HAVE_STRERROR */
1370             if (sval == NULL)
1371             {
1372                sprintf(tempbuf, "(errno = %d)", ival);
1373                sval = tempbuf;
1374             }
1375 #endif /* ndef _WIN32 */
1376             oldoutc = outc;
1377             outc += strlen(sval);
1378             if (outc < BUFFER_SIZE-1) 
1379             {
1380                strcpy(outbuf + oldoutc, sval);
1381             }
1382             else
1383             {
1384                outbuf[oldoutc] = '\0';
1385             }
1386             break;
1387          case 'T':
1388             /* Non-standard: Print a Common Log File timestamp */
1389             {
1390                /*
1391                 * Write timestamp into tempbuf.
1392                 *
1393                 * Complex because not all OSs have tm_gmtoff or
1394                 * the %z field in strftime()
1395                 */
1396                time_t now; 
1397                struct tm *tm_now; 
1398                struct tm gmt;
1399 #ifdef HAVE_LOCALTIME_R
1400                struct tm dummy;
1401 #endif
1402                int days, hrs, mins; 
1403                time (&now); 
1404 #ifdef HAVE_GMTIME_R
1405                gmt = *gmtime_r(&now, &gmt);
1406 #elif FEATURE_PTHREAD
1407                pthread_mutex_lock(&gmtime_mutex);
1408                gmt = *gmtime(&now);
1409                pthread_mutex_unlock(&gmtime_mutex);
1410 #else
1411                gmt = *gmtime(&now);
1412 #endif
1413 #ifdef HAVE_LOCALTIME_R
1414                tm_now = localtime_r(&now, &dummy);
1415 #elif FEATURE_PTHREAD
1416                pthread_mutex_lock(&localtime_mutex);
1417                tm_now = localtime (&now); 
1418                pthread_mutex_unlock(&localtime_mutex);
1419 #else
1420                tm_now = localtime (&now); 
1421 #endif
1422                days = tm_now->tm_yday - gmt.tm_yday; 
1423                hrs = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + tm_now->tm_hour - gmt.tm_hour); 
1424                mins = hrs * 60 + tm_now->tm_min - gmt.tm_min; 
1425                strftime (tempbuf, BUFFER_SIZE-6, "%d/%b/%Y:%H:%M:%S ", tm_now); 
1426                sprintf (tempbuf + strlen(tempbuf), "%+03d%02d", mins / 60, abs(mins) % 60); 
1427             }
1428             oldoutc = outc;
1429             outc += strlen(tempbuf);
1430             if (outc < BUFFER_SIZE-1) 
1431             {
1432                strcpy(outbuf + oldoutc, tempbuf);
1433             }
1434             else
1435             {
1436                outbuf[oldoutc] = '\0';
1437             }
1438             break;
1439          default:
1440             sprintf(outbuf, "Privoxy(%08lx) Error: log_error(): Bad format string:\n"
1441                             "Format = \"%s\"\n"
1442                             "Exiting.", this_thread, fmt);
1443             if( !logfp )
1444             {
1445                logfp = stderr;
1446             }
1447             fputs(outbuf_save, logfp);
1448             unlock_logfile();
1449             fatal_error(outbuf_save);
1450             /* Never get here */
1451             break;
1452
1453       } /* switch( p ) */
1454
1455    } /* for( p ... ) */
1456    
1457    /* done with var. args */
1458    va_end( ap );
1459    
1460    if (outc >= BUFFER_SIZE-2)
1461    {
1462       /* insufficient room for newline and trailing null. */
1463
1464       static const char warning[] = "... [too long, truncated]\n";
1465
1466       if (outc < BUFFER_SIZE)
1467       {
1468          /* Need to add terminating null in this case. */
1469          outbuf[outc] = '\0';
1470       }
1471
1472       /* Truncate output */
1473       outbuf[BUFFER_SIZE - sizeof(warning)] = '\0';
1474
1475       /* Append warning */
1476       strcat(outbuf, warning);
1477    }
1478    else
1479    {
1480       /* Add terminating newline and null */
1481       outbuf[outc++] = '\n';
1482       outbuf[outc] = '\0';
1483    }
1484
1485    /* deal with glibc stupidity - it won't let you initialize logfp */
1486    if( !logfp )
1487    {
1488       logfp = stderr;
1489    }
1490
1491    fputs(outbuf_save, logfp);
1492
1493    if (loglevel == LOG_LEVEL_FATAL)
1494    {
1495       fatal_error(outbuf_save);
1496       /* Never get here */
1497    }
1498
1499    unlock_logfile();
1500
1501 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
1502    /* Write to display */
1503    LogPutString(outbuf_save);
1504 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
1505
1506 }
1507 #endif /* defined(USE_NEW_LOG_ERROR) */
1508
1509
1510 #ifdef _WIN32
1511 /*********************************************************************
1512  *
1513  * Function    :  w32_socket_strerr
1514  *
1515  * Description :  Translate the return value from WSAGetLastError()
1516  *                into a string.
1517  *
1518  * Parameters  :
1519  *          1  :  errcode = The return value from WSAGetLastError().
1520  *          2  :  tmp_buf = A temporary buffer that might be used to
1521  *                          store the string.
1522  *
1523  * Returns     :  String representing the error code.  This may be
1524  *                a global string constant or a string stored in
1525  *                tmp_buf.
1526  *
1527  *********************************************************************/
1528 static char *w32_socket_strerr(int errcode, char *tmp_buf)
1529 {
1530 #define TEXT_FOR_ERROR(code,text) \
1531    if (errcode == code)           \
1532    {                              \
1533       return #code " - " text;    \
1534    }
1535
1536    TEXT_FOR_ERROR(WSAEACCES, "Permission denied")
1537    TEXT_FOR_ERROR(WSAEADDRINUSE, "Address already in use.")
1538    TEXT_FOR_ERROR(WSAEADDRNOTAVAIL, "Cannot assign requested address.");
1539    TEXT_FOR_ERROR(WSAEAFNOSUPPORT, "Address family not supported by protocol family.");
1540    TEXT_FOR_ERROR(WSAEALREADY, "Operation already in progress.");
1541    TEXT_FOR_ERROR(WSAECONNABORTED, "Software caused connection abort.");
1542    TEXT_FOR_ERROR(WSAECONNREFUSED, "Connection refused.");
1543    TEXT_FOR_ERROR(WSAECONNRESET, "Connection reset by peer.");
1544    TEXT_FOR_ERROR(WSAEDESTADDRREQ, "Destination address required.");
1545    TEXT_FOR_ERROR(WSAEFAULT, "Bad address.");
1546    TEXT_FOR_ERROR(WSAEHOSTDOWN, "Host is down.");
1547    TEXT_FOR_ERROR(WSAEHOSTUNREACH, "No route to host.");
1548    TEXT_FOR_ERROR(WSAEINPROGRESS, "Operation now in progress.");
1549    TEXT_FOR_ERROR(WSAEINTR, "Interrupted function call.");
1550    TEXT_FOR_ERROR(WSAEINVAL, "Invalid argument.");
1551    TEXT_FOR_ERROR(WSAEISCONN, "Socket is already connected.");
1552    TEXT_FOR_ERROR(WSAEMFILE, "Too many open sockets.");
1553    TEXT_FOR_ERROR(WSAEMSGSIZE, "Message too long.");
1554    TEXT_FOR_ERROR(WSAENETDOWN, "Network is down.");
1555    TEXT_FOR_ERROR(WSAENETRESET, "Network dropped connection on reset.");
1556    TEXT_FOR_ERROR(WSAENETUNREACH, "Network is unreachable.");
1557    TEXT_FOR_ERROR(WSAENOBUFS, "No buffer space available.");
1558    TEXT_FOR_ERROR(WSAENOPROTOOPT, "Bad protocol option.");
1559    TEXT_FOR_ERROR(WSAENOTCONN, "Socket is not connected.");
1560    TEXT_FOR_ERROR(WSAENOTSOCK, "Socket operation on non-socket.");
1561    TEXT_FOR_ERROR(WSAEOPNOTSUPP, "Operation not supported.");
1562    TEXT_FOR_ERROR(WSAEPFNOSUPPORT, "Protocol family not supported.");
1563    TEXT_FOR_ERROR(WSAEPROCLIM, "Too many processes.");
1564    TEXT_FOR_ERROR(WSAEPROTONOSUPPORT, "Protocol not supported.");
1565    TEXT_FOR_ERROR(WSAEPROTOTYPE, "Protocol wrong type for socket.");
1566    TEXT_FOR_ERROR(WSAESHUTDOWN, "Cannot send after socket shutdown.");
1567    TEXT_FOR_ERROR(WSAESOCKTNOSUPPORT, "Socket type not supported.");
1568    TEXT_FOR_ERROR(WSAETIMEDOUT, "Connection timed out.");
1569    TEXT_FOR_ERROR(WSAEWOULDBLOCK, "Resource temporarily unavailable.");
1570    TEXT_FOR_ERROR(WSAHOST_NOT_FOUND, "Host not found.");
1571    TEXT_FOR_ERROR(WSANOTINITIALISED, "Successful WSAStartup not yet performed.");
1572    TEXT_FOR_ERROR(WSANO_DATA, "Valid name, no data record of requested type.");
1573    TEXT_FOR_ERROR(WSANO_RECOVERY, "This is a non-recoverable error.");
1574    TEXT_FOR_ERROR(WSASYSNOTREADY, "Network subsystem is unavailable.");
1575    TEXT_FOR_ERROR(WSATRY_AGAIN, "Non-authoritative host not found.");
1576    TEXT_FOR_ERROR(WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range.");
1577    TEXT_FOR_ERROR(WSAEDISCON, "Graceful shutdown in progress.");
1578    /*
1579     * The following error codes are documented in the Microsoft WinSock
1580     * reference guide, but don't actually exist.
1581     *
1582     * TEXT_FOR_ERROR(WSA_INVALID_HANDLE, "Specified event object handle is invalid.");
1583     * TEXT_FOR_ERROR(WSA_INVALID_PARAMETER, "One or more parameters are invalid.");
1584     * TEXT_FOR_ERROR(WSAINVALIDPROCTABLE, "Invalid procedure table from service provider.");
1585     * TEXT_FOR_ERROR(WSAINVALIDPROVIDER, "Invalid service provider version number.");
1586     * TEXT_FOR_ERROR(WSA_IO_PENDING, "Overlapped operations will complete later.");
1587     * TEXT_FOR_ERROR(WSA_IO_INCOMPLETE, "Overlapped I/O event object not in signaled state.");
1588     * TEXT_FOR_ERROR(WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available.");
1589     * TEXT_FOR_ERROR(WSAPROVIDERFAILEDINIT, "Unable to initialize a service provider.");
1590     * TEXT_FOR_ERROR(WSASYSCALLFAILURE, "System call failure.");
1591     * TEXT_FOR_ERROR(WSA_OPERATION_ABORTED, "Overlapped operation aborted.");
1592     */
1593
1594    sprintf(tmp_buf, "(error number %d)", errcode);
1595    return tmp_buf;
1596 }
1597 #endif /* def _WIN32 */
1598
1599
1600 #ifdef __OS2__
1601 /*********************************************************************
1602  *
1603  * Function    :  os2_socket_strerr
1604  *
1605  * Description :  Translate the return value from sock_errno()
1606  *                into a string.
1607  *
1608  * Parameters  :
1609  *          1  :  errcode = The return value from sock_errno().
1610  *          2  :  tmp_buf = A temporary buffer that might be used to
1611  *                          store the string.
1612  *
1613  * Returns     :  String representing the error code.  This may be
1614  *                a global string constant or a string stored in
1615  *                tmp_buf.
1616  *
1617  *********************************************************************/
1618 static char *os2_socket_strerr(int errcode, char *tmp_buf)
1619 {
1620 #define TEXT_FOR_ERROR(code,text) \
1621    if (errcode == code)           \
1622    {                              \
1623       return #code " - " text;    \
1624    }
1625
1626    TEXT_FOR_ERROR(SOCEPERM          , "Not owner.")
1627    TEXT_FOR_ERROR(SOCESRCH          , "No such process.")
1628    TEXT_FOR_ERROR(SOCEINTR          , "Interrupted system call.")
1629    TEXT_FOR_ERROR(SOCENXIO          , "No such device or address.")
1630    TEXT_FOR_ERROR(SOCEBADF          , "Bad file number.")
1631    TEXT_FOR_ERROR(SOCEACCES         , "Permission denied.")
1632    TEXT_FOR_ERROR(SOCEFAULT         , "Bad address.")
1633    TEXT_FOR_ERROR(SOCEINVAL         , "Invalid argument.")
1634    TEXT_FOR_ERROR(SOCEMFILE         , "Too many open files.")
1635    TEXT_FOR_ERROR(SOCEPIPE          , "Broken pipe.")
1636    TEXT_FOR_ERROR(SOCEWOULDBLOCK    , "Operation would block.")
1637    TEXT_FOR_ERROR(SOCEINPROGRESS    , "Operation now in progress.")
1638    TEXT_FOR_ERROR(SOCEALREADY       , "Operation already in progress.")
1639    TEXT_FOR_ERROR(SOCENOTSOCK       , "Socket operation on non-socket.")
1640    TEXT_FOR_ERROR(SOCEDESTADDRREQ   , "Destination address required.")
1641    TEXT_FOR_ERROR(SOCEMSGSIZE       , "Message too long.")
1642    TEXT_FOR_ERROR(SOCEPROTOTYPE     , "Protocol wrong type for socket.")
1643    TEXT_FOR_ERROR(SOCENOPROTOOPT    , "Protocol not available.")
1644    TEXT_FOR_ERROR(SOCEPROTONOSUPPORT, "Protocol not supported.")
1645    TEXT_FOR_ERROR(SOCESOCKTNOSUPPORT, "Socket type not supported.")
1646    TEXT_FOR_ERROR(SOCEOPNOTSUPP     , "Operation not supported.")
1647    TEXT_FOR_ERROR(SOCEPFNOSUPPORT   , "Protocol family not supported.")
1648    TEXT_FOR_ERROR(SOCEAFNOSUPPORT   , "Address family not supported by protocol family.")
1649    TEXT_FOR_ERROR(SOCEADDRINUSE     , "Address already in use.")
1650    TEXT_FOR_ERROR(SOCEADDRNOTAVAIL  , "Can't assign requested address.")
1651    TEXT_FOR_ERROR(SOCENETDOWN       , "Network is down.")
1652    TEXT_FOR_ERROR(SOCENETUNREACH    , "Network is unreachable.")
1653    TEXT_FOR_ERROR(SOCENETRESET      , "Network dropped connection on reset.")
1654    TEXT_FOR_ERROR(SOCECONNABORTED   , "Software caused connection abort.")
1655    TEXT_FOR_ERROR(SOCECONNRESET     , "Connection reset by peer.")
1656    TEXT_FOR_ERROR(SOCENOBUFS        , "No buffer space available.")
1657    TEXT_FOR_ERROR(SOCEISCONN        , "Socket is already connected.")
1658    TEXT_FOR_ERROR(SOCENOTCONN       , "Socket is not connected.")
1659    TEXT_FOR_ERROR(SOCESHUTDOWN      , "Can't send after socket shutdown.")
1660    TEXT_FOR_ERROR(SOCETOOMANYREFS   , "Too many references: can't splice.")
1661    TEXT_FOR_ERROR(SOCETIMEDOUT      , "Operation timed out.")
1662    TEXT_FOR_ERROR(SOCECONNREFUSED   , "Connection refused.")
1663    TEXT_FOR_ERROR(SOCELOOP          , "Too many levels of symbolic links.")
1664    TEXT_FOR_ERROR(SOCENAMETOOLONG   , "File name too long.")
1665    TEXT_FOR_ERROR(SOCEHOSTDOWN      , "Host is down.")
1666    TEXT_FOR_ERROR(SOCEHOSTUNREACH   , "No route to host.")
1667    TEXT_FOR_ERROR(SOCENOTEMPTY      , "Directory not empty.")
1668    TEXT_FOR_ERROR(SOCEOS2ERR        , "OS/2 Error.")
1669
1670    sprintf(tmp_buf, "(error number %d)", errcode);
1671    return tmp_buf;
1672 }
1673 #endif /* def __OS2__ */
1674
1675
1676 /*
1677   Local Variables:
1678   tab-width: 3
1679   end:
1680 */