Finished the bulk of changes for gnupg 1.9. This included switching
[gnupg.git] / jnlib / logging.c
1 /* logging.c -  useful logging functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21
22 /* This file should replace logger.c in the future - for now it is not
23  * used by GnuPG but by GPA.
24  * It is a quite simple implemenation but sufficient for most purposes.
25  */
26
27 #include <config.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stdarg.h>
32 #include <errno.h>
33 #include <time.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #ifdef __MINGW32__
37   #include <io.h>
38 #endif
39
40 #define JNLIB_NEED_LOG_LOGV 1
41 #include "libjnlib-config.h"
42 #include "logging.h"
43
44
45 static FILE *logstream;
46 static char prefix_buffer[80];
47 static int with_time;
48 static int with_prefix;
49 static int with_pid;
50
51 static int missing_lf;
52 static int errorcount;
53
54 #if 0
55 static void
56 write2stderr( const char *s )
57 {
58     write( 2, s, strlen(s) );
59 }
60
61
62 static void
63 do_die(int rc, const char *text )
64 {
65     write2stderr("\nFatal error: ");
66     write2stderr(text);
67     write2stderr("\n");
68     abort();
69 }
70 #endif
71
72 int
73 log_get_errorcount (int clear)
74 {
75     int n = errorcount;
76     if( clear )
77         errorcount = 0;
78     return n;
79 }
80
81 void
82 log_inc_errorcount (void)
83 {
84    errorcount++;
85 }
86
87 void
88 log_set_file( const char *name )
89 {
90     FILE *fp = (name && strcmp(name,"-"))? fopen(name, "a") : stderr;
91     if( !fp ) {
92         fprintf(stderr, "failed to open log file `%s': %s\n",
93                                                 name, strerror(errno));
94         return;
95     }
96     setvbuf( fp, NULL, _IOLBF, 0 );
97
98     if (logstream && logstream != stderr && logstream != stdout)
99       fclose( logstream );
100     logstream = fp;
101     missing_lf = 0;
102 }
103
104 void
105 log_set_fd (int fd)
106 {
107   FILE *fp;
108   
109   if (fd == 1)
110     fp = stdout;
111   else if (fd == 2)
112     fp = stderr;
113   else
114     fp = fdopen (fd, "a");
115   if (!fp)
116     {
117       fprintf (stderr, "failed to fdopen log fd %d: %s\n",
118                fd, strerror(errno));
119       return;
120     }
121   setvbuf (fp, NULL, _IOLBF, 0);
122   
123   if (logstream && logstream != stderr && logstream != stdout)
124     fclose( logstream);
125   logstream = fp;
126   missing_lf = 0;
127 }
128
129
130 void
131 log_set_prefix (const char *text, unsigned int flags)
132 {
133   if (text)
134     {
135       strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
136       prefix_buffer[sizeof (prefix_buffer)-1] = 0;
137     }
138   
139   with_prefix = (flags & 1);
140   with_time = (flags & 2);
141   with_pid  = (flags & 4);
142 }
143
144
145 const char *
146 log_get_prefix (unsigned int *flags)
147 {
148   if (flags)
149     {
150       *flags = 0;
151       if (with_prefix)
152         *flags |= 1;
153       if (with_time)
154         *flags |= 2;
155       if (with_pid)
156         *flags |=4;
157     }
158   return prefix_buffer;
159 }
160
161 int
162 log_get_fd()
163 {
164     return fileno(logstream?logstream:stderr);
165 }
166
167 FILE *
168 log_get_stream ()
169 {
170     return logstream?logstream:stderr;
171 }
172
173
174 static void
175 do_logv( int level, const char *fmt, va_list arg_ptr )
176 {
177   if (!logstream)
178     logstream = stderr;
179
180   if (missing_lf && level != JNLIB_LOG_CONT)
181     putc('\n', logstream );
182   missing_lf = 0;
183
184   if (level != JNLIB_LOG_CONT)
185     { /* Note this does not work for multiple line logging as we would
186        * need to print to a buffer first */
187       if (with_time)
188         {
189           struct tm *tp;
190           time_t atime = time (NULL);
191           
192           tp = localtime (&atime);
193           fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
194                    1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
195                    tp->tm_hour, tp->tm_min, tp->tm_sec );
196         }
197       if (with_prefix)
198         fputs (prefix_buffer, logstream);
199       if (with_pid)
200         fprintf (logstream, "[%u]", (unsigned int)getpid ());
201       if (!with_time)
202         putc (':', logstream);
203       /* A leading backspace suppresses the extra space so that we can
204          correclty output, programname, filename and linenumber. */
205       if (fmt && *fmt == '\b')
206         fmt++;
207       else
208         putc (' ', logstream);
209     }
210
211   switch (level)
212     {
213     case JNLIB_LOG_BEGIN: break;
214     case JNLIB_LOG_CONT: break;
215     case JNLIB_LOG_INFO: break;
216     case JNLIB_LOG_WARN: break;
217     case JNLIB_LOG_ERROR: break;
218     case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
219     case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
220     case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
221     default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
222     }
223
224   if (fmt)
225     {
226       vfprintf(logstream,fmt,arg_ptr) ;
227       if (*fmt && fmt[strlen(fmt)-1] != '\n')
228         missing_lf = 1;
229     }
230
231   if (level == JNLIB_LOG_FATAL)
232     exit(2);
233   if (level == JNLIB_LOG_BUG)
234     abort();
235 }
236
237 static void
238 do_log( int level, const char *fmt, ... )
239 {
240     va_list arg_ptr ;
241
242     va_start( arg_ptr, fmt ) ;
243     do_logv( level, fmt, arg_ptr );
244     va_end(arg_ptr);
245 }
246
247
248 void
249 log_logv (int level, const char *fmt, va_list arg_ptr)
250 {
251   do_logv (level, fmt, arg_ptr);
252 }
253
254 void
255 log_info( const char *fmt, ... )
256 {
257     va_list arg_ptr ;
258
259     va_start( arg_ptr, fmt ) ;
260     do_logv( JNLIB_LOG_INFO, fmt, arg_ptr );
261     va_end(arg_ptr);
262 }
263
264 void
265 log_error( const char *fmt, ... )
266 {
267     va_list arg_ptr ;
268
269     va_start( arg_ptr, fmt ) ;
270     do_logv( JNLIB_LOG_ERROR, fmt, arg_ptr );
271     va_end(arg_ptr);
272     /* protect against counter overflow */
273     if( errorcount < 30000 )
274         errorcount++;
275 }
276
277
278 void
279 log_fatal( const char *fmt, ... )
280 {
281     va_list arg_ptr ;
282
283     va_start( arg_ptr, fmt ) ;
284     do_logv( JNLIB_LOG_FATAL, fmt, arg_ptr );
285     va_end(arg_ptr);
286     abort(); /* never called, but it makes the compiler happy */
287 }
288
289 void
290 log_bug( const char *fmt, ... )
291 {
292     va_list arg_ptr ;
293
294     va_start( arg_ptr, fmt ) ;
295     do_logv( JNLIB_LOG_BUG, fmt, arg_ptr );
296     va_end(arg_ptr);
297     abort(); /* never called, but it makes the compiler happy */
298 }
299
300 void
301 log_debug( const char *fmt, ... )
302 {
303     va_list arg_ptr ;
304
305     va_start( arg_ptr, fmt ) ;
306     do_logv( JNLIB_LOG_DEBUG, fmt, arg_ptr );
307     va_end(arg_ptr);
308 }
309
310
311 void
312 log_printf (const char *fmt, ...)
313 {
314   va_list arg_ptr;
315
316   va_start (arg_ptr, fmt);
317   do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, fmt, arg_ptr);
318   va_end (arg_ptr);
319 }
320
321 /* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
322    dump, with TEXT just an empty string, print a trailing linefeed,
323    otherwise print an entire debug line. */
324 void
325 log_printhex (const char *text, const void *buffer, size_t length)
326 {
327   if (text && *text)
328     log_debug ("%s ", text);
329   if (length)
330     {
331       const unsigned char *p = buffer;
332       log_printf ("%02X", *p);
333       for (length--, p++; length--; p++)
334         log_printf (" %02X", *p);
335     }
336   if (text)
337     log_printf ("\n");
338 }
339
340
341 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
342 void
343 bug_at( const char *file, int line, const char *func )
344 {
345     do_log( JNLIB_LOG_BUG,
346              ("... this is a bug (%s:%d:%s)\n"), file, line, func );
347     abort(); /* never called, but it makes the compiler happy */
348 }
349 #else
350 void
351 bug_at( const char *file, int line )
352 {
353     do_log( JNLIB_LOG_BUG,
354              _("you found a bug ... (%s:%d)\n"), file, line);
355     abort(); /* never called, but it makes the compiler happy */
356 }
357 #endif
358