2c0fddf2b590d7bba277b8f888b56e7412de5f5a
[privoxy.git] / errlog.c
1 const char errlog_rcs[] = "$Id: errlog.c,v 1.2 2001/05/17 22:42:01 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.2  2001/05/17 22:42:01  oes
37  *     - Cleaned CRLF's from the sources and related files
38  *     - Repaired logging for REF and FRC
39  *
40  *    Revision 1.1.1.1  2001/05/15 13:58:51  oes
41  *    Initial import of version 2.9.3 source tree
42  *
43  *
44  *********************************************************************/
45 \f
46
47 #include "config.h"
48
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <stdarg.h>
52 #include <string.h>
53
54 #ifndef _WIN32
55 #include <unistd.h>
56 #endif /* ndef _WIN32 */
57
58 #include <errno.h>
59 /* #include <pthread.h> */
60
61 #ifdef _WIN32
62 #include <windows.h>
63 #include "w32log.h"
64 #endif /* def _WIN32 */
65
66 #include "errlog.h"
67 #include "project.h"
68
69 const char errlog_h_rcs[] = ERRLOG_H_VERSION;
70 \r
71
72 /*\r
73  * LOG_LEVEL_FATAL, LOG_LEVEL_ERROR and LOG_LEVEL_INFO\r
74  * cannot be turned off.  (There are some exceptional situations\r
75  * where we need to get a message to the user).\r
76  *\r
77  * FIXME: Do we need LOG_LEVEL_INFO here?\r
78  */
79 #define LOG_LEVEL_MINIMUM  (LOG_LEVEL_FATAL | LOG_LEVEL_ERROR | LOG_LEVEL_INFO)
80
81 /* where to log (default: stderr) */
82 static FILE *logfp = NULL;
83
84 /* where to log (NULL == stderr) */
85 static char * logfilename = NULL;
86
87 /* logging detail level.  */
88 static int debug = LOG_LEVEL_MINIMUM;  
89
90 static void fatal_error(const char * error_message);\r
91 \r
92 \r
93 /*********************************************************************\r
94  *\r
95  * Function    :  fatal_error\r
96  *\r
97  * Description :  Displays a fatal error to standard error (or, on \r
98  *                a WIN32 GUI, to a dialog box), and exits\r
99  *                JunkBuster with status code 1.\r
100  *\r
101  * Parameters  :\r
102  *          1  :  error_message = The error message to display.\r
103  *\r
104  * Returns     :  Does not return.\r
105  *\r
106  *********************************************************************/\r
107 static void fatal_error(const char * error_message)\r
108 {\r
109 #if defined(_WIN32) && !defined(_WIN_CONSOLE)\r
110    MessageBox(NULL, error_message, "Internet JunkBuster Error", \r
111       MB_OK | MB_ICONERROR | MB_TASKMODAL | MB_SETFOREGROUND | MB_TOPMOST);  \r
112 #else /* if !defined(_WIN32) || defined(_WIN_CONSOLE) */\r
113    fputs(error_message, stderr);\r
114 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */\r
115 \r
116    exit(1);\r
117 }\r
118 \r
119
120 /*********************************************************************
121  *
122  * Function    :  init_errlog
123  *
124  * Description :  Initializes the logging module.  Must call before
125  *                calling log_error.
126  *
127  * Parameters  :
128  *          1  :  prog_name  = The program name.
129  *          2  :  logfname   = The logfile name, or NULL for stderr.
130  *          3  :  debuglevel = The debugging level.
131  *
132  * Returns     :  N/A
133  *
134  *********************************************************************/
135 void init_error_log(const char *prog_name, const char *logfname, int debuglevel)
136 {
137    FILE *fp;
138
139    /* FIXME RACE HAZARD: should start critical section error_log_use here */
140
141    /* set the logging detail level */
142    debug = debuglevel | LOG_LEVEL_MINIMUM;
143
144    if ((logfp != NULL) && (logfp != stderr))
145    {
146       fclose(logfp);
147    }
148    logfp = stderr;
149
150    /* set the designated log file */
151    if( logfname )
152    {
153       if( !(fp = fopen(logfname, "a")) )
154       {\r
155          log_error(LOG_LEVEL_FATAL, "init_errlog(): can't open logfile: %s", logfname);
156       }
157
158       /* set logging to be completely unbuffered */
159       setbuf(fp, NULL);
160
161       logfp = fp;
162    }
163
164    log_error(LOG_LEVEL_INFO, "Internet JunkBuster version " VERSION);
165    if (prog_name != NULL)
166    {
167       log_error(LOG_LEVEL_INFO, "Program name: %s", prog_name);
168    }
169
170    /* FIXME RACE HAZARD: should end critical section error_log_use here */
171
172 } /* init_error_log */
173
174
175 /*********************************************************************
176  *
177  * Function    :  log_error
178  *
179  * Description :  This is the error-reporting and logging function.
180  *
181  * Parameters  :
182  *          1  :  loglevel  = the type of message to be logged
183  *          2  :  fmt       = the main string we want logged, printf-like
184  *          3  :  ...       = arguments to be inserted in fmt (printf-like).
185  *
186  * Returns     :  N/A
187  *
188  *********************************************************************/
189 void log_error(int loglevel, char *fmt, ...)
190 {
191    va_list ap;
192    char outbuf[BUFSIZ];
193    char * src = fmt;
194    int outc = 0;
195    long this_thread = 1;  /* was: pthread_t this_thread;*/
196
197    /* verify if loglevel applies to current settings and bail out if negative */
198    if(!(loglevel & debug))
199    {
200                 return;
201    }
202
203    /* FIXME get current thread id */
204    /* this_thread = (long)pthread_self(); */
205
206    switch (loglevel)
207    {
208       case LOG_LEVEL_ERROR:\r
209          outc = sprintf(outbuf, "IJB(%d) Error: ", this_thread);\r
210          break;\r
211       case LOG_LEVEL_FATAL:\r
212          outc = sprintf(outbuf, "IJB(%d) Fatal error: ", this_thread);\r
213          break;\r
214       case LOG_LEVEL_GPC:
215          outc = sprintf(outbuf, "IJB(%d) Request: ", this_thread);
216          break;
217       case LOG_LEVEL_CONNECT:
218          outc = sprintf(outbuf, "IJB(%d) Connect: ", this_thread);
219          break;
220       case LOG_LEVEL_HEADER:
221          outc = sprintf(outbuf, "IJB(%d) Header: ", this_thread);
222          break;
223       case LOG_LEVEL_INFO:\r
224          outc = sprintf(outbuf, "IJB(%d) Info: ", this_thread);\r
225          break;\r
226       case LOG_LEVEL_RE_FILTER:
227          outc = sprintf(outbuf, "IJB(%d) Re-Filter: ", this_thread);
228          break;
229       case LOG_LEVEL_FORCE:
230          outc = sprintf(outbuf, "IJB(%d) Force: ", this_thread);
231          break;\r
232       default:
233          outc = sprintf(outbuf, "IJB(%d) UNKNOWN LOG TYPE(%d): ", this_thread, loglevel);
234          break;
235    }
236    
237    /* get ready to scan var. args. */
238    va_start( ap, fmt );
239
240    /* build formatted message from fmt and var-args */
241    while ((*src) && (outc < BUFSIZ-2))
242    {
243       char tempbuf[BUFSIZ];
244       char *sval;
245       int ival;
246       unsigned uval;
247       long lval;
248       unsigned long ulval;
249       int oldoutc;
250       char ch;
251       
252       ch = *src++;
253       if( ch != '%' )
254       {
255          outbuf[outc++] = ch;
256          continue;
257       }
258
259       ch = *src++;
260       switch (ch) {
261          case '%':
262             outbuf[outc++] = '%';
263             break;
264          case 'd':
265             ival = va_arg( ap, int );
266             oldoutc = outc;
267             outc += sprintf(tempbuf, "%d", ival);
268             if (outc < BUFSIZ-1) 
269             {
270                strcpy(outbuf + oldoutc, tempbuf);
271             }
272             else
273             {
274                outbuf[oldoutc] = '\0';
275             }
276             break;
277          case 'u':
278             uval = va_arg( ap, unsigned );
279             oldoutc = outc;
280             outc += sprintf(tempbuf, "%u", uval);
281             if (outc < BUFSIZ-1) 
282             {
283                strcpy(outbuf + oldoutc, tempbuf);
284             }
285             else
286             {
287                outbuf[oldoutc] = '\0';
288             }
289             break;
290          case 'l':
291             /* this is a modifier that must be followed by u or d */
292             ch = *src++;
293             if (ch == 'd')
294             {
295                lval = va_arg( ap, long );
296                oldoutc = outc;
297                outc += sprintf(tempbuf, "%ld", lval);
298             }
299             else if (ch == 'u')
300             {
301                ulval = va_arg( ap, unsigned long );
302                oldoutc = outc;
303                outc += sprintf(tempbuf, "%lu", ulval);
304             }
305             else
306             {
307                /* Error */
308                sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
309                                "Format = \"%s\"\n"
310                                "Exiting.", this_thread, fmt);
311                /* FIXME RACE HAZARD: should start critical section error_log_use here */
312                if( !logfp )
313                {
314                   logfp = stderr;
315                }
316                fputs(outbuf, logfp);
317                /* FIXME RACE HAZARD: should end critical section error_log_use here */
318                fatal_error(outbuf);\r
319                /* Never get here */\r
320                break;
321             }
322             if (outc < BUFSIZ-1) 
323             {
324                strcpy(outbuf + oldoutc, tempbuf);
325             }
326             else
327             {
328                outbuf[oldoutc] = '\0';
329             }
330             break;
331          case 'c':
332             /*
333              * Note that char paramaters are converted to int, so we need to
334              * pass "int" to va_arg.  (See K&R, 2nd ed, section A7.3.2, page 202)
335              */
336             outbuf[outc++] = (char) va_arg( ap, int );
337             break;
338          case 's':
339             sval = va_arg( ap, char * );
340             oldoutc = outc;
341             outc += strlen(sval);
342             if (outc < BUFSIZ-1) 
343             {
344                strcpy(outbuf + oldoutc, sval);
345             }
346             else
347             {
348                outbuf[oldoutc] = '\0';
349             }
350             break;
351          case 'E':
352             /* Non-standard: Print error code from errno */
353             ival = errno;
354 #ifndef NOSTRERROR
355             sval = strerror(ival);
356 #else /* def NOSTRERROR */
357             sval = NULL
358 #endif /* def NOSTRERROR */
359             if (sval == NULL)
360             {
361                sprintf(tempbuf, "(errno = %d)", ival);
362                sval = tempbuf;
363             }
364             oldoutc = outc;
365             outc += strlen(sval);
366             if (outc < BUFSIZ-1) 
367             {
368                strcpy(outbuf + oldoutc, sval);
369             }
370             else
371             {
372                outbuf[oldoutc] = '\0';
373             }
374             break;
375          default:
376             sprintf(outbuf, "IJB(%d) Error: log_error(): Bad format string:\n"
377                             "Format = \"%s\"\n"
378                             "Exiting.", this_thread, fmt);
379             /* FIXME RACE HAZARD: should start critical section error_log_use here */
380             if( !logfp )
381             {
382                logfp = stderr;
383             }
384             fputs(outbuf, logfp);
385             /* FIXME RACE HAZARD: should end critical section error_log_use here */
386             fatal_error(outbuf);\r
387             /* Never get here */\r
388             break;
389
390       } /* switch( p ) */
391
392    } /* for( p ... ) */
393    
394    /* done with var. args */
395    va_end( ap );
396    
397    if (outc >= BUFSIZ-2)
398    {
399       /* insufficient room for newline and trailing null. */
400
401       static const char warning[] = "... [too long, truncated]\n";
402
403       if (outc < BUFSIZ)
404       {
405          /* Need to add terminating null in this case. */
406          outbuf[outc] = '\0';
407       }
408
409       /* Truncate output */
410       outbuf[BUFSIZ - sizeof(warning)] = '\0';
411
412       /* Append warning */
413       strcat(outbuf, warning);
414    }
415    else
416    {
417       /* Add terminating newline and null */
418       outbuf[outc++] = '\n';
419       outbuf[outc] = '\0';
420    }
421
422    /* FIXME RACE HAZARD: should start critical section error_log_use here */
423
424    /* deal with glibc stupidity - it won't let you initialize logfp */
425    if( !logfp )
426    {
427       logfp = stderr;
428    }
429
430    fputs(outbuf, logfp);
431
432    if (loglevel == LOG_LEVEL_FATAL)\r
433    {\r
434       fatal_error(outbuf);\r
435       /* Never get here */\r
436    }\r
437 \r
438    /* FIXME RACE HAZARD: should end critical section error_log_use here */
439 \r
440 #if defined(_WIN32) && !defined(_WIN_CONSOLE)
441    /* Write to display */
442    LogPutString(outbuf);
443    LogShowActivity();
444 #endif /* defined(_WIN32) && !defined(_WIN_CONSOLE) */
445
446 }
447
448
449 /*
450   Local Variables:
451   tab-width: 3
452   end:
453 */
454