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