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