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