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