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