(log_set_file): Do not close an old logstream if it
[gnupg.git] / jnlib / logging.c
1 /* logging.c -  useful logging functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003,
3  *               2004 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22
23 /* This file should replace logger.c in the future - for now it is not
24  * used by GnuPG but by GPA.
25  * It is a quite simple implemenation but sufficient for most purposes.
26  */
27
28 #include <config.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <stddef.h>
34 #include <errno.h>
35 #include <time.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/un.h>
39 #include <unistd.h>
40 #ifdef __MINGW32__
41 #  include <io.h>
42 #endif
43
44 #define JNLIB_NEED_LOG_LOGV 1
45 #include "libjnlib-config.h"
46 #include "logging.h"
47
48
49 static FILE *logstream;
50 static int log_socket = -1;
51 static char prefix_buffer[80];
52 static int with_time;
53 static int with_prefix;
54 static int with_pid;
55 static int running_detached;
56 static int force_prefixes;
57
58 static int missing_lf;
59 static int errorcount;
60
61 #if 0
62 static void
63 write2stderr( const char *s )
64 {
65     write( 2, s, strlen(s) );
66 }
67
68
69 static void
70 do_die(int rc, const char *text )
71 {
72     write2stderr("\nFatal error: ");
73     write2stderr(text);
74     write2stderr("\n");
75     abort();
76 }
77 #endif
78
79 int
80 log_get_errorcount (int clear)
81 {
82     int n = errorcount;
83     if( clear )
84         errorcount = 0;
85     return n;
86 }
87
88 void
89 log_inc_errorcount (void)
90 {
91    errorcount++;
92 }
93
94
95 /* The follwing 3 functions are used by funopen to write logs to a
96    socket. */
97 #if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
98 struct fun_cookie_s {
99   int fd;
100   int quiet;
101   char name[1];
102 };
103
104 /* Write NBYTES of BUF to file descriptor FD. */
105 static int
106 writen (int fd, const unsigned char *buf, size_t nbytes)
107 {
108   size_t nleft = nbytes;
109   int nwritten;
110   
111   while (nleft > 0)
112     {
113       nwritten = write (fd, buf, nleft);
114       if (nwritten < 0 && errno == EINTR)
115         continue;
116       if (nwritten < 0)
117         return -1;
118       nleft -= nwritten;
119       buf = buf + nwritten;
120     }
121   
122   return 0;
123 }
124
125
126 static int 
127 fun_writer (void *cookie_arg, const char *buffer, size_t size)
128 {
129   struct fun_cookie_s *cookie = cookie_arg;
130
131   /* Note that we always try to reconnect to the socket but print
132      error messages only the first time an error occured.  If
133      RUNNING_DETACHED is set we don't fall back to stderr and even do
134      not print any error messages.  This is needed because detached
135      processes often close stderr and by writing to file descriptor 2
136      we might send the log message to a file not intended for logging
137      (e.g. a pipe or network connection). */
138   if (cookie->fd == -1)
139     {
140       /* Not yet open or meanwhile closed due to an error. */
141       struct sockaddr_un addr;
142       size_t addrlen;
143
144       cookie->fd = socket (PF_LOCAL, SOCK_STREAM, 0);
145       if (cookie->fd == -1)
146         {
147           if (!cookie->quiet && !running_detached)
148             fprintf (stderr, "failed to create socket for logging: %s\n",
149                      strerror(errno));
150           goto failure;
151         }
152       log_socket = cookie->fd;
153       
154       memset (&addr, 0, sizeof addr);
155       addr.sun_family = PF_LOCAL;
156       strncpy (addr.sun_path, cookie->name, sizeof (addr.sun_path)-1);
157       addr.sun_path[sizeof (addr.sun_path)-1] = 0;
158       addrlen = (offsetof (struct sockaddr_un, sun_path)
159                  + strlen (addr.sun_path) + 1);
160       
161       if (connect (cookie->fd, (struct sockaddr *) &addr, addrlen) == -1)
162         {
163           log_socket = -1;
164           if (!cookie->quiet && !running_detached)
165             fprintf (stderr, "can't connect to `%s': %s\n",
166                      cookie->name, strerror(errno));
167           close (cookie->fd);
168           cookie->fd = -1;
169           goto failure;
170         }
171       /* Connection established. */
172       cookie->quiet = 0;
173     }
174   
175   if (!writen (cookie->fd, buffer, size))
176     return size; /* Okay. */ 
177
178   log_socket = -1;
179   if (!running_detached)
180     fprintf (stderr, "error writing to `%s': %s\n",
181              cookie->name, strerror(errno));
182   close (cookie->fd);
183   cookie->fd = -1;
184
185  failure: 
186   if (!running_detached)
187     {
188       if (!cookie->quiet)
189         {
190           fputs ("switching logging to stderr\n", stderr);
191           cookie->quiet = 1;
192         }
193       
194       fwrite (buffer, size, 1, stderr);
195     }
196   return size;
197 }
198
199 static int
200 fun_closer (void *cookie_arg)
201 {
202   struct fun_cookie_s *cookie = cookie_arg;
203
204   if (cookie->fd != -1)
205     close (cookie->fd);
206   jnlib_free (cookie);
207   return 0;
208 }
209 #endif /* HAVE_FOPENCOOKIE || HAVE_FUNOPEN */
210
211
212
213
214 /* Set the file to write log to.  The special names NULL and "-" may
215    be used to select stderr and names formatted like
216    "socket:///home/foo/mylogs" may be used to write the logging to the
217    socket "/home/foo/mylogs".  If the connection to the socket fails
218    or a write error is detected, the function writes to stderr and
219    tries the next time again to connect the socket.
220   */
221 void
222 log_set_file (const char *name) 
223 {
224   FILE *fp;
225
226   force_prefixes = 0;
227   if (name && !strncmp (name, "socket://", 9) && name[9])
228     {
229 #if defined (HAVE_FOPENCOOKIE)||  defined (HAVE_FUNOPEN)
230       struct fun_cookie_s *cookie;
231
232       cookie = jnlib_xmalloc (sizeof *cookie + strlen (name+9));
233       cookie->fd = -1;
234       cookie->quiet = 0;
235       strcpy (cookie->name, name+9);
236
237 #ifdef HAVE_FOPENCOOKIE
238       {
239         cookie_io_functions_t io = { NULL };
240         io.write = fun_writer;
241         io.close = fun_closer;
242
243         fp = fopencookie (cookie, "w", io);
244       }
245 #else /*!HAVE_FOPENCOOKIE*/
246       {
247         fp = funopen (cookie, NULL, fun_writer, NULL, fun_closer);
248       }
249 #endif /*!HAVE_FOPENCOOKIE*/
250 #else /* Neither fopencookie nor funopen. */
251       {
252         fprintf (stderr, "system does not support logging to a socket - "
253                  "using stderr\n");
254         fp = stderr;
255       }
256 #endif /* Neither fopencookie nor funopen. */
257
258       /* We always need to print the prefix and the pid, so that the
259          server reading the socket can do something meaningful. */
260       force_prefixes = 1;
261       /* On success close the old logstream right now, so that we are
262          really sure it has been closed. */
263       if (fp && logstream)
264         {
265           if (logstream != stderr && logstream != stdout)
266             fclose (logstream);
267           logstream = NULL;
268         }
269     }
270   else
271     fp = (name && strcmp(name,"-"))? fopen (name, "a") : stderr;
272   if (!fp)
273     {
274       fprintf (stderr, "failed to open log file `%s': %s\n",
275                name? name:"[stderr]", strerror(errno));
276       return;
277     }
278   setvbuf (fp, NULL, _IOLBF, 0);
279   
280   if (logstream && logstream != stderr && logstream != stdout)
281     fclose (logstream);
282   logstream = fp;
283   missing_lf = 0;
284 }
285
286
287 void
288 log_set_fd (int fd)
289 {
290   FILE *fp;
291
292   force_prefixes = 0;
293   if (fd == 1)
294     fp = stdout;
295   else if (fd == 2)
296     fp = stderr;
297   else
298     fp = fdopen (fd, "a");
299   if (!fp)
300     {
301       fprintf (stderr, "failed to fdopen log fd %d: %s\n",
302                fd, strerror(errno));
303       return;
304     }
305   setvbuf (fp, NULL, _IOLBF, 0);
306   
307   if (logstream && logstream != stderr && logstream != stdout)
308     fclose( logstream);
309   logstream = fp;
310   missing_lf = 0;
311 }
312
313
314 void
315 log_set_prefix (const char *text, unsigned int flags)
316 {
317   if (text)
318     {
319       strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
320       prefix_buffer[sizeof (prefix_buffer)-1] = 0;
321     }
322   
323   with_prefix = (flags & JNLIB_LOG_WITH_PREFIX);
324   with_time = (flags & JNLIB_LOG_WITH_TIME);
325   with_pid  = (flags & JNLIB_LOG_WITH_PID);
326   running_detached = (flags & JNLIB_LOG_RUN_DETACHED);
327 }
328
329
330 const char *
331 log_get_prefix (unsigned int *flags)
332 {
333   if (flags)
334     {
335       *flags = 0;
336       if (with_prefix)
337         *flags |= JNLIB_LOG_WITH_PREFIX;
338       if (with_time)
339         *flags |= JNLIB_LOG_WITH_TIME;
340       if (with_pid)
341         *flags |= JNLIB_LOG_WITH_PID;
342       if (running_detached)
343         *flags |= JNLIB_LOG_RUN_DETACHED;
344     }
345   return prefix_buffer;
346 }
347
348 /* This function returns true if the file descriptor FD is in use for
349    logging.  This is preferable over a test using log_get_fd in that
350    it allows the logging code to use more then one file descriptor. */
351 int
352 log_test_fd (int fd)
353 {
354   if (fileno (logstream?logstream:stderr) == fd)
355     return 1;
356   if (log_socket == fd)
357     return 1;
358   return 0;
359 }
360
361 int
362 log_get_fd ()
363 {
364   return fileno(logstream?logstream:stderr);
365 }
366
367 FILE *
368 log_get_stream ()
369 {
370   return logstream?logstream:stderr;
371 }
372
373
374 static void
375 do_logv (int level, const char *fmt, va_list arg_ptr)
376 {
377   if (!logstream)
378     logstream = stderr;
379
380   if (missing_lf && level != JNLIB_LOG_CONT)
381     putc('\n', logstream );
382   missing_lf = 0;
383
384   if (level != JNLIB_LOG_CONT)
385     { /* Note this does not work for multiple line logging as we would
386        * need to print to a buffer first */
387       if (with_time && !force_prefixes)
388         {
389           struct tm *tp;
390           time_t atime = time (NULL);
391           
392           tp = localtime (&atime);
393           fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
394                    1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
395                    tp->tm_hour, tp->tm_min, tp->tm_sec );
396         }
397       if (with_prefix || force_prefixes)
398         fputs (prefix_buffer, logstream);
399       if (with_pid || force_prefixes)
400         fprintf (logstream, "[%u]", (unsigned int)getpid ());
401       if (!with_time || force_prefixes)
402         putc (':', logstream);
403       /* A leading backspace suppresses the extra space so that we can
404          correctly output, programname, filename and linenumber. */
405       if (fmt && *fmt == '\b')
406         fmt++;
407       else
408         putc (' ', logstream);
409     }
410
411   switch (level)
412     {
413     case JNLIB_LOG_BEGIN: break;
414     case JNLIB_LOG_CONT: break;
415     case JNLIB_LOG_INFO: break;
416     case JNLIB_LOG_WARN: break;
417     case JNLIB_LOG_ERROR: break;
418     case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
419     case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
420     case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
421     default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
422     }
423
424
425   if (fmt)
426     {
427       vfprintf(logstream,fmt,arg_ptr) ;
428       if (*fmt && fmt[strlen(fmt)-1] != '\n')
429         missing_lf = 1;
430     }
431
432   if (level == JNLIB_LOG_FATAL)
433     exit(2);
434   if (level == JNLIB_LOG_BUG)
435     abort();
436 }
437
438 static void
439 do_log( int level, const char *fmt, ... )
440 {
441     va_list arg_ptr ;
442
443     va_start( arg_ptr, fmt ) ;
444     do_logv( level, fmt, arg_ptr );
445     va_end(arg_ptr);
446 }
447
448
449 void
450 log_logv (int level, const char *fmt, va_list arg_ptr)
451 {
452   do_logv (level, fmt, arg_ptr);
453 }
454
455 void
456 log_info( const char *fmt, ... )
457 {
458     va_list arg_ptr ;
459
460     va_start( arg_ptr, fmt ) ;
461     do_logv( JNLIB_LOG_INFO, fmt, arg_ptr );
462     va_end(arg_ptr);
463 }
464
465 void
466 log_error( const char *fmt, ... )
467 {
468     va_list arg_ptr ;
469
470     va_start( arg_ptr, fmt ) ;
471     do_logv( JNLIB_LOG_ERROR, fmt, arg_ptr );
472     va_end(arg_ptr);
473     /* protect against counter overflow */
474     if( errorcount < 30000 )
475         errorcount++;
476 }
477
478
479 void
480 log_fatal( const char *fmt, ... )
481 {
482     va_list arg_ptr ;
483
484     va_start( arg_ptr, fmt ) ;
485     do_logv( JNLIB_LOG_FATAL, fmt, arg_ptr );
486     va_end(arg_ptr);
487     abort(); /* never called, but it makes the compiler happy */
488 }
489
490 void
491 log_bug( const char *fmt, ... )
492 {
493     va_list arg_ptr ;
494
495     va_start( arg_ptr, fmt ) ;
496     do_logv( JNLIB_LOG_BUG, fmt, arg_ptr );
497     va_end(arg_ptr);
498     abort(); /* never called, but it makes the compiler happy */
499 }
500
501 void
502 log_debug( const char *fmt, ... )
503 {
504     va_list arg_ptr ;
505
506     va_start( arg_ptr, fmt ) ;
507     do_logv( JNLIB_LOG_DEBUG, fmt, arg_ptr );
508     va_end(arg_ptr);
509 }
510
511
512 void
513 log_printf (const char *fmt, ...)
514 {
515   va_list arg_ptr;
516
517   va_start (arg_ptr, fmt);
518   do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, fmt, arg_ptr);
519   va_end (arg_ptr);
520 }
521
522 /* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
523    dump, with TEXT just an empty string, print a trailing linefeed,
524    otherwise print an entire debug line. */
525 void
526 log_printhex (const char *text, const void *buffer, size_t length)
527 {
528   if (text && *text)
529     log_debug ("%s ", text);
530   if (length)
531     {
532       const unsigned char *p = buffer;
533       log_printf ("%02X", *p);
534       for (length--, p++; length--; p++)
535         log_printf (" %02X", *p);
536     }
537   if (text)
538     log_printf ("\n");
539 }
540
541
542 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
543 void
544 bug_at( const char *file, int line, const char *func )
545 {
546     do_log( JNLIB_LOG_BUG,
547              ("... this is a bug (%s:%d:%s)\n"), file, line, func );
548     abort(); /* never called, but it makes the compiler happy */
549 }
550 #else
551 void
552 bug_at( const char *file, int line )
553 {
554     do_log( JNLIB_LOG_BUG,
555              _("you found a bug ... (%s:%d)\n"), file, line);
556     abort(); /* never called, but it makes the compiler happy */
557 }
558 #endif
559