Moving source files to src/
[privoxy.git] / src / errlog.c
1 const char errlog_rcs[] = "$Id: errlog.c,v 1.40 2002/05/22 01:27:27 david__schmidt 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 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.40  2002/05/22 01:27:27  david__schmidt
37  *
38  *    Add os2_socket_strerr mirroring w32_socket_strerr.
39  *
40  *    Revision 1.39  2002/04/03 17:15:27  gliptak
41  *    zero padding thread ids in log
42  *
43  *    Revision 1.38  2002/03/31 17:18:59  jongfoster
44  *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
45  *
46  *    Revision 1.37  2002/03/27 14:32:43  david__schmidt
47  *    More compiler warning message maintenance
48  *
49  *    Revision 1.36  2002/03/26 22:29:54  swa
50  *    we have a new homepage!
51  *
52  *    Revision 1.35  2002/03/24 15:23:33  jongfoster
53  *    Name changes
54  *
55  *    Revision 1.34  2002/03/24 13:25:43  swa
56  *    name change related issues
57  *
58  *    Revision 1.33  2002/03/13 00:27:04  jongfoster
59  *    Killing warnings
60  *
61  *    Revision 1.32  2002/03/07 03:46:17  oes
62  *    Fixed compiler warnings
63  *
64  *    Revision 1.31  2002/03/06 23:02:57  jongfoster
65  *    Removing tabs
66  *
67  *    Revision 1.30  2002/03/05 22:43:45  david__schmidt
68  *    - Better error reporting on OS/2
69  *    - Fix double-slash comment (oops)
70  *
71  *    Revision 1.29  2002/03/04 23:45:13  jongfoster
72  *    Printing thread ID if using Win32 native threads
73  *
74  *    Revision 1.28  2002/03/04 17:59:59  oes
75  *    Deleted deletePidFile(), cosmetics
76  *
77  *    Revision 1.27  2002/03/04 02:08:01  david__schmidt
78  *    Enable web editing of actions file on OS/2 (it had been broken all this time!)
79  *
80  *    Revision 1.26  2002/01/09 19:05:45  steudten
81  *    Fix big memory leak.
82  *
83  *    Revision 1.25  2002/01/09 14:32:08  oes
84  *    Added support for gmtime_r and localtime_r.
85  *
86  *    Revision 1.24  2001/12/30 14:07:32  steudten
87  *    - Add signal handling (unix)
88  *    - Add SIGHUP handler (unix)
89  *    - Add creation of pidfile (unix)
90  *    - Add action 'top' in rc file (RH)
91  *    - Add entry 'SIGNALS' to manpage
92  *    - Add exit message to logfile (unix)
93  *
94  *    Revision 1.23  2001/11/07 00:02:13  steudten
95  *    Add line number in error output for lineparsing for
96  *    actionsfile and configfile.
97  *    Special handling for CLF added.
98  *
99  *    Revision 1.22  2001/11/05 23:43:05  steudten
100  *    Add time+date to log files.
101  *
102  *    Revision 1.21  2001/10/25 03:40:47  david__schmidt
103  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
104  *    threads to call select() simultaneously.  So, it's time to do a real, live,
105  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
106  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
107  *
108  *    Revision 1.20  2001/09/16 23:04:34  jongfoster
109  *    Fixing a warning
110  *
111  *    Revision 1.19  2001/09/13 20:08:06  jongfoster
112  *    Adding support for LOG_LEVEL_CGI
113  *
114  *    Revision 1.18  2001/09/10 11:27:24  oes
115  *    Declaration of w32_socket_strerr now conditional
116  *
117  *    Revision 1.17  2001/09/10 10:17:13  oes
118  *    Removed unused variable; Fixed sprintf format
119  *
120  *    Revision 1.16  2001/07/30 22:08:36  jongfoster
121  *    Tidying up #defines:
122  *    - All feature #defines are now of the form FEATURE_xxx
123  *    - Permanently turned off WIN_GUI_EDIT
124  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
125  *
126  *    Revision 1.15  2001/07/29 17:41:10  jongfoster
127  *    Now prints thread ID for each message (pthreads only)
128  *
129  *    Revision 1.14  2001/07/19 19:03:48  haroon
130  *    - Added case for LOG_LEVEL_POPUPS
131  *
132  *    Revision 1.13  2001/07/13 13:58:58  oes
133  *     - Added case for LOG_LEVEL_DEANIMATE
134  *     - Removed all #ifdef PCRS
135  *
136  *    Revision 1.12  2001/06/09 10:55:28  jongfoster
137  *    Changing BUFSIZ ==> BUFFER_SIZE
138  *
139  *    Revision 1.11  2001/06/01 18:14:49  jongfoster
140  *    Changing the calls to strerr() to check HAVE_STRERR (which is defined
141  *    in config.h if appropriate) rather than the NO_STRERR macro.
142  *
143  *    Revision 1.10  2001/05/29 11:52:21  oes
144  *    Conditional compilation of w32_socket_error
145  *
146  *    Revision 1.9  2001/05/28 16:15:17  jongfoster
147  *    Improved reporting of errors under Win32.
148  *
149  *    Revision 1.8  2001/05/26 17:25:14  jongfoster
150  *    Added support for CLF (Common Log Format) and fixed LOG_LEVEL_LOG
151  *
152  *    Revision 1.7  2001/05/26 15:21:28  jongfoster
153  *    Activity animation in Win32 GUI now works even if debug==0
154  *
155  *    Revision 1.6  2001/05/25 21:55:08  jongfoster
156  *    Now cleans up properly on FATAL (removes taskbar icon etc)
157  *
158  *    Revision 1.5  2001/05/22 18:46:04  oes
159  *
160  *    - Enabled filtering banners by size rather than URL
161  *      by adding patterns that replace all standard banner
162  *      sizes with the "Junkbuster" gif to the re_filterfile
163  *
164  *    - Enabled filtering WebBugs by providing a pattern
165  *      which kills all 1x1 images
166  *
167  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
168  *      which is selected by the (nonstandard and therefore
169  *      capital) letter 'U' in the option string.
170  *      It causes the quantifiers to be ungreedy by default.
171  *      Appending a ? turns back to greedy (!).
172  *
173  *    - Added a new interceptor ijb-send-banner, which
174  *      sends back the "Junkbuster" gif. Without imagelist or
175  *      MSIE detection support, or if tinygif = 1, or the
176  *      URL isn't recognized as an imageurl, a lame HTML
177  *      explanation is sent instead.
178  *
179  *    - Added new feature, which permits blocking remote
180  *      script redirects and firing back a local redirect
181  *      to the browser.
182  *      The feature is conditionally compiled, i.e. it
183  *      can be disabled with --disable-fast-redirects,
184  *      plus it must be activated by a "fast-redirects"
185  *      line in the config file, has its own log level
186  *      and of course wants to be displayed by show-proxy-args
187  *      Note: Boy, all the #ifdefs in 1001 locations and
188  *      all the fumbling with configure.in and acconfig.h
189  *      were *way* more work than the feature itself :-(
190  *
191  *    - Because a generic redirect template was needed for
192  *      this, tinygif = 3 now uses the same.
193  *
194  *    - Moved GIFs, and other static HTTP response templates
195  *      to project.h
196  *
197  *    - Some minor fixes
198  *
199  *    - Removed some >400 CRs again (Jon, you really worked
200  *      a lot! ;-)
201  *
202  *    Revision 1.4  2001/05/21 19:32:54  jongfoster
203  *    Added another #ifdef _WIN_CONSOLE
204  *
205  *    Revision 1.3  2001/05/20 01:11:40  jongfoster
206  *    Added support for LOG_LEVEL_FATAL
207  *    Renamed LOG_LEVEL_FRC to LOG_LEVEL_FORCE,
208  *    and LOG_LEVEL_REF to LOG_LEVEL_RE_FILTER
209  *
210  *    Revision 1.2  2001/05/17 22:42:01  oes
211  *     - Cleaned CRLF's from the sources and related files
212  *     - Repaired logging for REF and FRC
213  *
214  *    Revision 1.1.1.1  2001/05/15 13:58:51  oes
215  *    Initial import of version 2.9.3 source tree
216  *
217  *
218  *********************************************************************/
219 \f
220
221 #include "config.h"
222 #include "miscutil.h"
223
224 #include <stdlib.h>
225 #include <stdio.h>
226 #include <stdarg.h>
227 #include <string.h>
228
229 #if !defined(_WIN32) && !defined(__OS2__)
230 #include <unistd.h>
231 #endif /* !defined(_WIN32) && !defined(__OS2__) */
232
233 #include <errno.h>
234 #include <assert.h>
235 #ifdef FEATURE_PTHREAD
236 #include <pthread.h>
237 #endif /* def FEATURE_PTHREAD */
238
239 #ifdef _WIN32
240 #ifndef STRICT
241 #define STRICT
242 #endif
243 #include <windows.h>
244 #ifndef _WIN_CONSOLE
245 #include "w32log.h"
246 #endif /* ndef _WIN_CONSOLE */
247 #endif /* def _WIN32 */
248
249 #ifdef __OS2__
250 #include <sys/socket.h> /* For sock_errno */
251 #define INCL_DOS
252 #include <os2.h>
253 #endif
254
255 #include "errlog.h"
256 #include "project.h"
257 #include "jcc.h"
258
259 const char errlog_h_rcs[] = ERRLOG_H_VERSION;
260
261
262 /*
263  * LOG_LEVEL_FATAL cannot be turned off.  (There are
264  * some exceptional situations where we need to get a
265  * message to the user).
266  */
267 #define LOG_LEVEL_MINIMUM  LOG_LEVEL_FATAL
268
269 /* where to log (default: stderr) */
270 static FILE *logfp = NULL;
271
272 /* logging detail level.  */
273 static int debug = (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR | LOG_LEVEL_INFO);  
274
275 /* static functions */
276 static void fatal_error(const char * error_message);
277 #ifdef _WIN32
278 static char *w32_socket_strerr(int errcode, char *tmp_buf);
279 #endif
280 #ifdef __OS2__
281 static char *os2_socket_strerr(int errcode, char *tmp_buf);
282 #endif
283
284 /*********************************************************************
285  *
286  * Function    :  fatal_error
287  *
288  * Description :  Displays a fatal error to standard error (or, on 
289  *                a WIN32 GUI, to a dialog box), and exits
290  *                JunkBuster with status code 1.
291  *
292  * Parameters  :
293  *          1  :  error_message = The error message to display.
294  *
295  * Returns     :  Does not return.
296  *
297  *********************************************************************/
298 static void fatal_error(const char * error_message)
299 {
300 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
301    MessageBox(g_hwndLogFrame, error_message, "Privoxy Error", 
302       MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  
303
304    /* Cleanup - remove taskbar icon etc. */
305    TermLogWindow();
306
307 #else /* if !defined(_WIN32) || defined(_WIN_CONSOLE) */
308    fputs(error_message, stderr);
309 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
310
311 #if defined(unix)
312    unlink(pidfile);
313 #endif /* unix */
314
315    exit(1);
316 }
317
318
319 /*********************************************************************
320  *
321  * Function    :  init_error_log
322  *
323  * Description :  Initializes the logging module.  Must call before
324  *                calling log_error.
325  *
326  * Parameters  :
327  *          1  :  prog_name  = The program name.
328  *          2  :  logfname   = The logfile name, or NULL for stderr.
329  *          3  :  debuglevel = The debugging level.
330  *
331  * Returns     :  N/A
332  *
333  *********************************************************************/
334 void init_error_log(const char *prog_name, const char *logfname, int debuglevel)
335 {
336    FILE *fp;
337
338    /* FIXME RACE HAZARD: should start critical section error_log_use here */
339
340    /* set the logging detail level */
341    debug = debuglevel | LOG_LEVEL_MINIMUM;
342
343    if ((logfp != NULL) && (logfp != stderr))
344    {
345       log_error(LOG_LEVEL_INFO, "(Re-)Open logfile %s", logfname ? logfname : "none");
346       fclose(logfp);
347    }
348    logfp = stderr;
349
350    /* set the designated log file */
351    if( logfname )
352    {
353       if( NULL == (fp = fopen(logfname, "a")) )
354       {
355          log_error(LOG_LEVEL_FATAL, "init_error_log(): can't open logfile: %s", logfname);
356       }
357
358       /* set logging to be completely unbuffered */
359       setbuf(fp, NULL);
360
361       logfp = fp;
362    }
363
364    log_error(LOG_LEVEL_INFO, "Privoxy version " VERSION);
365    if (prog_name != NULL)
366    {
367       log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
368    }
369
370    /* FIXME RACE HAZARD: should end critical section error_log_use here */
371
372 } /* init_error_log */
373
374
375 /*********************************************************************
376  *
377  * Function    :  log_error
378  *
379  * Description :  This is the error-reporting and logging function.
380  *
381  * Parameters  :
382  *          1  :  loglevel  = the type of message to be logged
383  *          2  :  fmt       = the main string we want logged, printf-like
384  *          3  :  ...       = arguments to be inserted in fmt (printf-like).
385  *
386  * Returns     :  N/A
387  *
388  *********************************************************************/
389 void log_error(int loglevel, char *fmt, ...)
390 {
391    va_list ap;
392    char *outbuf= NULL;
393    static char *outbuf_save = NULL;
394    char * src = fmt;
395    int outc = 0;
396    long this_thread = 1;  /* was: pthread_t this_thread;*/
397 #ifdef __OS2__
398    PTIB     ptib;
399    APIRET   ulrc;
400 #endif /* __OS2__ */
401
402 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
403    /*
404     * Irrespective of debug setting, a GET/POST/CONNECT makes
405     * the taskbar icon animate.  (There is an option to disable
406     * this but checking that is handled inside LogShowActivity()).
407     */
408    if (loglevel == LOG_LEVEL_GPC)
409    {
410       LogShowActivity();
411    }
412 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
413
414    /* verify if loglevel applies to current settings and bail out if negative */
415    if ((loglevel & debug) == 0)
416    {
417       return;
418    }
419
420    /* FIXME get current thread id */
421 #ifdef FEATURE_PTHREAD
422    this_thread = (long)pthread_self();
423 #elif defined(_WIN32)
424    this_thread = GetCurrentThreadId();
425 #elif defined(__OS2__)
426    ulrc = DosGetInfoBlocks(&ptib, NULL);
427    if (ulrc == 0)
428      this_thread = ptib -> tib_ptib2 -> tib2_ultid;
429 #endif /* def FEATURE_PTHREAD */
430
431    if ( !outbuf_save ) 
432    {
433       outbuf_save = outbuf = (char*)malloc(BUFFER_SIZE);
434       assert(outbuf);
435    }
436    outbuf = outbuf_save;
437
438     {
439        /*
440         * Write timestamp into tempbuf.
441         *
442         * Complex because not all OSs have tm_gmtoff or
443         * the %z field in strftime()
444         */
445        time_t now; 
446        struct tm tm_now; 
447        time (&now);
448 #ifdef HAVE_LOCALTIME_R
449        tm_now = *localtime_r(&now, &tm_now);
450 #else
451        tm_now = *localtime (&now); 
452 #endif
453        strftime(outbuf, BUFFER_SIZE-6, "%b %d %H:%M:%S ", &tm_now); 
454        outbuf += strlen( outbuf );
455     }
456    switch (loglevel)
457    {
458       case LOG_LEVEL_ERROR:
459          outc = sprintf(outbuf, "Privoxy(%05ld) Error: ", this_thread);
460          break;
461       case LOG_LEVEL_FATAL:
462          outc = sprintf(outbuf, "Privoxy(%05ld) Fatal error: ", this_thread);
463          break;
464       case LOG_LEVEL_GPC:
465          outc = sprintf(outbuf, "Privoxy(%05ld) Request: ", this_thread);
466          break;
467       case LOG_LEVEL_CONNECT:
468          outc = sprintf(outbuf, "Privoxy(%05ld) Connect: ", this_thread);
469          break;
470       case LOG_LEVEL_LOG:
471          outc = sprintf(outbuf, "Privoxy(%05ld) Writing: ", this_thread);
472          break;
473       case LOG_LEVEL_HEADER:
474          outc = sprintf(outbuf, "Privoxy(%05ld) Header: ", this_thread);
475          break;
476       case LOG_LEVEL_INFO:
477          outc = sprintf(outbuf, "Privoxy(%05ld) Info: ", this_thread);
478          break;
479       case LOG_LEVEL_RE_FILTER:
480          outc = sprintf(outbuf, "Privoxy(%05ld) Re-Filter: ", this_thread);
481          break;
482 #ifdef FEATURE_FORCE_LOAD
483       case LOG_LEVEL_FORCE:
484          outc = sprintf(outbuf, "Privoxy(%05ld) Force: ", this_thread);
485          break;
486 #endif /* def FEATURE_FORCE_LOAD */
487 #ifdef FEATURE_FAST_REDIRECTS
488       case LOG_LEVEL_REDIRECTS:
489          outc = sprintf(outbuf, "Privoxy(%05ld) Redirect: ", this_thread);
490          break;
491 #endif /* def FEATURE_FAST_REDIRECTS */
492       case LOG_LEVEL_DEANIMATE:
493          outc = sprintf(outbuf, "Privoxy(%05ld) Gif-Deanimate: ", this_thread);
494          break;
495       case LOG_LEVEL_CLF:
496          outbuf = outbuf_save;
497          outc = 0;
498          outbuf[0] = '\0';
499          break;
500 #ifdef FEATURE_KILL_POPUPS
501       case LOG_LEVEL_POPUPS:
502          outc = sprintf(outbuf, "Privoxy(%05ld) Kill-Popups: ", this_thread);
503          break;
504 #endif /* def FEATURE_KILL_POPUPS */
505       case LOG_LEVEL_CGI:
506          outc = sprintf(outbuf, "Privoxy(%05ld) CGI: ", this_thread);
507          break;
508       default:
509          outc = sprintf(outbuf, "Privoxy(%05ld) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
510          break;
511    }
512    
513    /* get ready to scan var. args. */
514    va_start( ap, fmt );
515
516    /* build formatted message from fmt and var-args */
517    while ((*src) && (outc < BUFFER_SIZE-2))
518    {
519       char tempbuf[BUFFER_SIZE];
520       char *sval = NULL;
521       int ival;
522       unsigned uval;
523       long lval;
524       unsigned long ulval;
525       int oldoutc;
526       char ch;
527       
528       ch = *src++;
529       if( ch != '%' )
530       {
531          outbuf[outc++] = ch;
532          continue;
533       }
534
535       ch = *src++;
536       switch (ch) {
537          case '%':
538             outbuf[outc++] = '%';
539             break;
540          case 'd':
541             ival = va_arg( ap, int );
542             oldoutc = outc;
543             outc += sprintf(tempbuf, "%d", ival);
544             if (outc < BUFFER_SIZE-1) 
545             {
546                strcpy(outbuf + oldoutc, tempbuf);
547             }
548             else
549             {
550                outbuf[oldoutc] = '\0';
551             }
552             break;
553          case 'u':
554             uval = va_arg( ap, unsigned );
555             oldoutc = outc;
556             outc += sprintf(tempbuf, "%u", uval);
557             if (outc < BUFFER_SIZE-1) 
558             {
559                strcpy(outbuf + oldoutc, tempbuf);
560             }
561             else
562             {
563                outbuf[oldoutc] = '\0';
564             }
565             break;
566          case 'l':
567             /* this is a modifier that must be followed by u or d */
568             ch = *src++;
569             if (ch == 'd')
570             {
571                lval = va_arg( ap, long );
572                oldoutc = outc;
573                outc += sprintf(tempbuf, "%ld", lval);
574             }
575             else if (ch == 'u')
576             {
577                ulval = va_arg( ap, unsigned long );
578                oldoutc = outc;
579                outc += sprintf(tempbuf, "%lu", ulval);
580             }
581             else
582             {
583                /* Error */
584                sprintf(outbuf, "Privoxy(%ld) Error: log_error(): Bad format string:\n"
585                                "Format = \"%s\"\n"
586                                "Exiting.", this_thread, fmt);
587                /* FIXME RACE HAZARD: should start critical section error_log_use here */
588                if( !logfp )
589                {
590                   logfp = stderr;
591                }
592                fputs(outbuf, logfp);
593                /* FIXME RACE HAZARD: should end critical section error_log_use here */
594                fatal_error(outbuf);
595                /* Never get here */
596                break;
597             }
598             if (outc < BUFFER_SIZE-1) 
599             {
600                strcpy(outbuf + oldoutc, tempbuf);
601             }
602             else
603             {
604                outbuf[oldoutc] = '\0';
605             }
606             break;
607          case 'c':
608             /*
609              * Note that char paramaters are converted to int, so we need to
610              * pass "int" to va_arg.  (See K&R, 2nd ed, section A7.3.2, page 202)
611              */
612             outbuf[outc++] = (char) va_arg( ap, int );
613             break;
614          case 's':
615             sval = va_arg( ap, char * );
616             oldoutc = outc;
617             outc += strlen(sval);
618             if (outc < BUFFER_SIZE-1) 
619             {
620                strcpy(outbuf + oldoutc, sval);
621             }
622             else
623             {
624                outbuf[oldoutc] = '\0';
625             }
626             break;
627          case 'N':
628             /* Non-standard: Print a counted string.  Takes 2 parameters:
629              * int length, const char * string
630              */
631             ival = va_arg( ap, int );
632             sval = va_arg( ap, char * );
633             if (ival < 0)
634             {
635                ival = 0;
636             }
637             oldoutc = outc;
638             outc += ival;
639             if (outc < BUFFER_SIZE-1)
640             {
641                memcpy(outbuf + oldoutc, sval, (size_t) ival);
642             }
643             else
644             {
645                outbuf[oldoutc] = '\0';
646             }
647             break;
648          case 'E':
649             /* Non-standard: Print error code from errno */
650 #ifdef _WIN32
651             ival = WSAGetLastError();
652             sval = w32_socket_strerr(ival, tempbuf);
653 #elif __OS2__
654             ival = sock_errno();
655             if (ival != 0)
656               sval = os2_socket_strerr(ival, tempbuf);
657             else
658             {
659               ival = errno;
660               sval = strerror(ival);
661             }
662 #else /* ifndef _WIN32 */
663             ival = errno; 
664 #ifdef HAVE_STRERROR
665             sval = strerror(ival);
666 #else /* ifndef HAVE_STRERROR */
667             sval = NULL;
668 #endif /* ndef HAVE_STRERROR */
669             if (sval == NULL)
670             {
671                sprintf(tempbuf, "(errno = %d)", ival);
672                sval = tempbuf;
673             }
674 #endif /* ndef _WIN32 */
675             oldoutc = outc;
676             outc += strlen(sval);
677             if (outc < BUFFER_SIZE-1) 
678             {
679                strcpy(outbuf + oldoutc, sval);
680             }
681             else
682             {
683                outbuf[oldoutc] = '\0';
684             }
685             break;
686          case 'T':
687             /* Non-standard: Print a Common Log File timestamp */
688             {
689                /*
690                 * Write timestamp into tempbuf.
691                 *
692                 * Complex because not all OSs have tm_gmtoff or
693                 * the %z field in strftime()
694                 */
695                time_t now; 
696                struct tm *tm_now; 
697                struct tm gmt;
698 #ifdef HAVE_LOCALTIME_R
699                struct tm dummy;
700 #endif
701                int days, hrs, mins; 
702                time (&now); 
703 #ifdef HAVE_GMTIME_R
704                gmt = *gmtime_r(&now, &gmt);
705 #else
706                gmt = *gmtime(&now);
707 #endif
708 #ifdef HAVE_LOCALTIME_R
709                tm_now = localtime_r(&now, &dummy);
710 #else
711                tm_now = localtime (&now); 
712 #endif
713                days = tm_now->tm_yday - gmt.tm_yday; 
714                hrs = ((days < -1 ? 24 : 1 < days ? -24 : days * 24) + tm_now->tm_hour - gmt.tm_hour); 
715                mins = hrs * 60 + tm_now->tm_min - gmt.tm_min; 
716                strftime (tempbuf, BUFFER_SIZE-6, "%d/%b/%Y:%H:%M:%S ", tm_now); 
717                sprintf (tempbuf + strlen(tempbuf), "%+03d%02d", mins / 60, abs(mins) % 60); 
718             }
719             oldoutc = outc;
720             outc += strlen(tempbuf);
721             if (outc < BUFFER_SIZE-1) 
722             {
723                strcpy(outbuf + oldoutc, tempbuf);
724             }
725             else
726             {
727                outbuf[oldoutc] = '\0';
728             }
729             break;
730          default:
731             sprintf(outbuf, "Privoxy(%ld) Error: log_error(): Bad format string:\n"
732                             "Format = \"%s\"\n"
733                             "Exiting.", this_thread, fmt);
734             /* FIXME RACE HAZARD: should start critical section error_log_use here */
735             if( !logfp )
736             {
737                logfp = stderr;
738             }
739             fputs(outbuf_save, logfp);
740             /* FIXME RACE HAZARD: should end critical section error_log_use here */
741             fatal_error(outbuf_save);
742             /* Never get here */
743             break;
744
745       } /* switch( p ) */
746
747    } /* for( p ... ) */
748    
749    /* done with var. args */
750    va_end( ap );
751    
752    if (outc >= BUFFER_SIZE-2)
753    {
754       /* insufficient room for newline and trailing null. */
755
756       static const char warning[] = "... [too long, truncated]\n";
757
758       if (outc < BUFFER_SIZE)
759       {
760          /* Need to add terminating null in this case. */
761          outbuf[outc] = '\0';
762       }
763
764       /* Truncate output */
765       outbuf[BUFFER_SIZE - sizeof(warning)] = '\0';
766
767       /* Append warning */
768       strcat(outbuf, warning);
769    }
770    else
771    {
772       /* Add terminating newline and null */
773       outbuf[outc++] = '\n';
774       outbuf[outc] = '\0';
775    }
776
777    /* FIXME RACE HAZARD: should start critical section error_log_use here */
778
779    /* deal with glibc stupidity - it won't let you initialize logfp */
780    if( !logfp )
781    {
782       logfp = stderr;
783    }
784
785    fputs(outbuf_save, logfp);
786
787    if (loglevel == LOG_LEVEL_FATAL)
788    {
789       fatal_error(outbuf_save);
790       /* Never get here */
791    }
792
793    /* FIXME RACE HAZARD: should end critical section error_log_use here */
794
795 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
796    /* Write to display */
797    LogPutString(outbuf_save);
798 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
799
800 }
801
802
803 #ifdef _WIN32
804 /*********************************************************************
805  *
806  * Function    :  w32_socket_strerr
807  *
808  * Description :  Translate the return value from WSAGetLastError()
809  *                into a string.
810  *
811  * Parameters  :
812  *          1  :  errcode = The return value from WSAGetLastError().
813  *          2  :  tmp_buf = A temporary buffer that might be used to
814  *                          store the string.
815  *
816  * Returns     :  String representing the error code.  This may be
817  *                a global string constant or a string stored in
818  *                tmp_buf.
819  *
820  *********************************************************************/
821 static char *w32_socket_strerr(int errcode, char *tmp_buf)
822 {
823 #define TEXT_FOR_ERROR(code,text) \
824    if (errcode == code)           \
825    {                              \
826       return #code " - " text;    \
827    }
828
829    TEXT_FOR_ERROR(WSAEACCES, "Permission denied")
830    TEXT_FOR_ERROR(WSAEADDRINUSE, "Address already in use.")
831    TEXT_FOR_ERROR(WSAEADDRNOTAVAIL, "Cannot assign requested address.");
832    TEXT_FOR_ERROR(WSAEAFNOSUPPORT, "Address family not supported by protocol family.");
833    TEXT_FOR_ERROR(WSAEALREADY, "Operation already in progress.");
834    TEXT_FOR_ERROR(WSAECONNABORTED, "Software caused connection abort.");
835    TEXT_FOR_ERROR(WSAECONNREFUSED, "Connection refused.");
836    TEXT_FOR_ERROR(WSAECONNRESET, "Connection reset by peer.");
837    TEXT_FOR_ERROR(WSAEDESTADDRREQ, "Destination address required.");
838    TEXT_FOR_ERROR(WSAEFAULT, "Bad address.");
839    TEXT_FOR_ERROR(WSAEHOSTDOWN, "Host is down.");
840    TEXT_FOR_ERROR(WSAEHOSTUNREACH, "No route to host.");
841    TEXT_FOR_ERROR(WSAEINPROGRESS, "Operation now in progress.");
842    TEXT_FOR_ERROR(WSAEINTR, "Interrupted function call.");
843    TEXT_FOR_ERROR(WSAEINVAL, "Invalid argument.");
844    TEXT_FOR_ERROR(WSAEISCONN, "Socket is already connected.");
845    TEXT_FOR_ERROR(WSAEMFILE, "Too many open sockets.");
846    TEXT_FOR_ERROR(WSAEMSGSIZE, "Message too long.");
847    TEXT_FOR_ERROR(WSAENETDOWN, "Network is down.");
848    TEXT_FOR_ERROR(WSAENETRESET, "Network dropped connection on reset.");
849    TEXT_FOR_ERROR(WSAENETUNREACH, "Network is unreachable.");
850    TEXT_FOR_ERROR(WSAENOBUFS, "No buffer space available.");
851    TEXT_FOR_ERROR(WSAENOPROTOOPT, "Bad protocol option.");
852    TEXT_FOR_ERROR(WSAENOTCONN, "Socket is not connected.");
853    TEXT_FOR_ERROR(WSAENOTSOCK, "Socket operation on non-socket.");
854    TEXT_FOR_ERROR(WSAEOPNOTSUPP, "Operation not supported.");
855    TEXT_FOR_ERROR(WSAEPFNOSUPPORT, "Protocol family not supported.");
856    TEXT_FOR_ERROR(WSAEPROCLIM, "Too many processes.");
857    TEXT_FOR_ERROR(WSAEPROTONOSUPPORT, "Protocol not supported.");
858    TEXT_FOR_ERROR(WSAEPROTOTYPE, "Protocol wrong type for socket.");
859    TEXT_FOR_ERROR(WSAESHUTDOWN, "Cannot send after socket shutdown.");
860    TEXT_FOR_ERROR(WSAESOCKTNOSUPPORT, "Socket type not supported.");
861    TEXT_FOR_ERROR(WSAETIMEDOUT, "Connection timed out.");
862    TEXT_FOR_ERROR(WSAEWOULDBLOCK, "Resource temporarily unavailable.");
863    TEXT_FOR_ERROR(WSAHOST_NOT_FOUND, "Host not found.");
864    TEXT_FOR_ERROR(WSANOTINITIALISED, "Successful WSAStartup not yet performed.");
865    TEXT_FOR_ERROR(WSANO_DATA, "Valid name, no data record of requested type.");
866    TEXT_FOR_ERROR(WSANO_RECOVERY, "This is a non-recoverable error.");
867    TEXT_FOR_ERROR(WSASYSNOTREADY, "Network subsystem is unavailable.");
868    TEXT_FOR_ERROR(WSATRY_AGAIN, "Non-authoritative host not found.");
869    TEXT_FOR_ERROR(WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range.");
870    TEXT_FOR_ERROR(WSAEDISCON, "Graceful shutdown in progress.");
871    /*
872     * The following error codes are documented in the Microsoft WinSock
873     * reference guide, but don't actually exist.
874     *
875     * TEXT_FOR_ERROR(WSA_INVALID_HANDLE, "Specified event object handle is invalid.");
876     * TEXT_FOR_ERROR(WSA_INVALID_PARAMETER, "One or more parameters are invalid.");
877     * TEXT_FOR_ERROR(WSAINVALIDPROCTABLE, "Invalid procedure table from service provider.");
878     * TEXT_FOR_ERROR(WSAINVALIDPROVIDER, "Invalid service provider version number.");
879     * TEXT_FOR_ERROR(WSA_IO_PENDING, "Overlapped operations will complete later.");
880     * TEXT_FOR_ERROR(WSA_IO_INCOMPLETE, "Overlapped I/O event object not in signaled state.");
881     * TEXT_FOR_ERROR(WSA_NOT_ENOUGH_MEMORY, "Insufficient memory available.");
882     * TEXT_FOR_ERROR(WSAPROVIDERFAILEDINIT, "Unable to initialize a service provider.");
883     * TEXT_FOR_ERROR(WSASYSCALLFAILURE, "System call failure.");
884     * TEXT_FOR_ERROR(WSA_OPERATION_ABORTED, "Overlapped operation aborted.");
885     */
886
887    sprintf(tmp_buf, "(error number %d)", errcode);
888    return tmp_buf;
889 }
890 #endif /* def _WIN32 */
891
892
893 #ifdef __OS2__
894 /*********************************************************************
895  *
896  * Function    :  os2_socket_strerr
897  *
898  * Description :  Translate the return value from sock_errno()
899  *                into a string.
900  *
901  * Parameters  :
902  *          1  :  errcode = The return value from sock_errno().
903  *          2  :  tmp_buf = A temporary buffer that might be used to
904  *                          store the string.
905  *
906  * Returns     :  String representing the error code.  This may be
907  *                a global string constant or a string stored in
908  *                tmp_buf.
909  *
910  *********************************************************************/
911 static char *os2_socket_strerr(int errcode, char *tmp_buf)
912 {
913 #define TEXT_FOR_ERROR(code,text) \
914    if (errcode == code)           \
915    {                              \
916       return #code " - " text;    \
917    }
918
919    TEXT_FOR_ERROR(SOCEPERM          , "Not owner.")
920    TEXT_FOR_ERROR(SOCESRCH          , "No such process.")
921    TEXT_FOR_ERROR(SOCEINTR          , "Interrupted system call.")
922    TEXT_FOR_ERROR(SOCENXIO          , "No such device or address.")
923    TEXT_FOR_ERROR(SOCEBADF          , "Bad file number.")
924    TEXT_FOR_ERROR(SOCEACCES         , "Permission denied.")
925    TEXT_FOR_ERROR(SOCEFAULT         , "Bad address.")
926    TEXT_FOR_ERROR(SOCEINVAL         , "Invalid argument.")
927    TEXT_FOR_ERROR(SOCEMFILE         , "Too many open files.")
928    TEXT_FOR_ERROR(SOCEPIPE          , "Broken pipe.")
929    TEXT_FOR_ERROR(SOCEWOULDBLOCK    , "Operation would block.")
930    TEXT_FOR_ERROR(SOCEINPROGRESS    , "Operation now in progress.")
931    TEXT_FOR_ERROR(SOCEALREADY       , "Operation already in progress.")
932    TEXT_FOR_ERROR(SOCENOTSOCK       , "Socket operation on non-socket.")
933    TEXT_FOR_ERROR(SOCEDESTADDRREQ   , "Destination address required.")
934    TEXT_FOR_ERROR(SOCEMSGSIZE       , "Message too long.")
935    TEXT_FOR_ERROR(SOCEPROTOTYPE     , "Protocol wrong type for socket.")
936    TEXT_FOR_ERROR(SOCENOPROTOOPT    , "Protocol not available.")
937    TEXT_FOR_ERROR(SOCEPROTONOSUPPORT, "Protocol not supported.")
938    TEXT_FOR_ERROR(SOCESOCKTNOSUPPORT, "Socket type not supported.")
939    TEXT_FOR_ERROR(SOCEOPNOTSUPP     , "Operation not supported.")
940    TEXT_FOR_ERROR(SOCEPFNOSUPPORT   , "Protocol family not supported.")
941    TEXT_FOR_ERROR(SOCEAFNOSUPPORT   , "Address family not supported by protocol family.")
942    TEXT_FOR_ERROR(SOCEADDRINUSE     , "Address already in use.")
943    TEXT_FOR_ERROR(SOCEADDRNOTAVAIL  , "Can't assign requested address.")
944    TEXT_FOR_ERROR(SOCENETDOWN       , "Network is down.")
945    TEXT_FOR_ERROR(SOCENETUNREACH    , "Network is unreachable.")
946    TEXT_FOR_ERROR(SOCENETRESET      , "Network dropped connection on reset.")
947    TEXT_FOR_ERROR(SOCECONNABORTED   , "Software caused connection abort.")
948    TEXT_FOR_ERROR(SOCECONNRESET     , "Connection reset by peer.")
949    TEXT_FOR_ERROR(SOCENOBUFS        , "No buffer space available.")
950    TEXT_FOR_ERROR(SOCEISCONN        , "Socket is already connected.")
951    TEXT_FOR_ERROR(SOCENOTCONN       , "Socket is not connected.")
952    TEXT_FOR_ERROR(SOCESHUTDOWN      , "Can't send after socket shutdown.")
953    TEXT_FOR_ERROR(SOCETOOMANYREFS   , "Too many references: can't splice.")
954    TEXT_FOR_ERROR(SOCETIMEDOUT      , "Operation timed out.")
955    TEXT_FOR_ERROR(SOCECONNREFUSED   , "Connection refused.")
956    TEXT_FOR_ERROR(SOCELOOP          , "Too many levels of symbolic links.")
957    TEXT_FOR_ERROR(SOCENAMETOOLONG   , "File name too long.")
958    TEXT_FOR_ERROR(SOCEHOSTDOWN      , "Host is down.")
959    TEXT_FOR_ERROR(SOCEHOSTUNREACH   , "No route to host.")
960    TEXT_FOR_ERROR(SOCENOTEMPTY      , "Directory not empty.")
961    TEXT_FOR_ERROR(SOCEOS2ERR        , "OS/2 Error.")
962
963    sprintf(tmp_buf, "(error number %d)", errcode);
964    return tmp_buf;
965 }
966 #endif /* def __OS2__ */
967
968
969 /*
970   Local Variables:
971   tab-width: 3
972   end:
973 */