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