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