* gpg-agent.c (parse_rereadable_options): New arg REREAD. Allow
[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 becuase detached
135      processes often close stderr and my printing to fiel 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       /* Note 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 meanigful. */
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)
264         {
265           fclose (logstream);
266           logstream = NULL;
267         }
268     }
269   else
270     fp = (name && strcmp(name,"-"))? fopen (name, "a") : stderr;
271   if (!fp)
272     {
273       fprintf (stderr, "failed to open log file `%s': %s\n",
274                name? name:"[stderr]", strerror(errno));
275       return;
276     }
277   setvbuf (fp, NULL, _IOLBF, 0);
278   
279   if (logstream && logstream != stderr && logstream != stdout)
280     fclose (logstream);
281   logstream = fp;
282   missing_lf = 0;
283 }
284
285
286 void
287 log_set_fd (int fd)
288 {
289   FILE *fp;
290
291   force_prefixes = 0;
292   if (fd == 1)
293     fp = stdout;
294   else if (fd == 2)
295     fp = stderr;
296   else
297     fp = fdopen (fd, "a");
298   if (!fp)
299     {
300       fprintf (stderr, "failed to fdopen log fd %d: %s\n",
301                fd, strerror(errno));
302       return;
303     }
304   setvbuf (fp, NULL, _IOLBF, 0);
305   
306   if (logstream && logstream != stderr && logstream != stdout)
307     fclose( logstream);
308   logstream = fp;
309   missing_lf = 0;
310 }
311
312
313 void
314 log_set_prefix (const char *text, unsigned int flags)
315 {
316   if (text)
317     {
318       strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
319       prefix_buffer[sizeof (prefix_buffer)-1] = 0;
320     }
321   
322   with_prefix = (flags & JNLIB_LOG_WITH_PREFIX);
323   with_time = (flags & JNLIB_LOG_WITH_TIME);
324   with_pid  = (flags & JNLIB_LOG_WITH_PID);
325   running_detached = (flags & JNLIB_LOG_RUN_DETACHED);
326 }
327
328
329 const char *
330 log_get_prefix (unsigned int *flags)
331 {
332   if (flags)
333     {
334       *flags = 0;
335       if (with_prefix)
336         *flags |= JNLIB_LOG_WITH_PREFIX;
337       if (with_time)
338         *flags |= JNLIB_LOG_WITH_TIME;
339       if (with_pid)
340         *flags |= JNLIB_LOG_WITH_PID;
341       if (running_detached)
342         *flags |= JNLIB_LOG_RUN_DETACHED;
343     }
344   return prefix_buffer;
345 }
346
347 /* This function returns true if the file descriptor FD is in use for
348    logging.  This is preferable over a test using log_get_fd in that
349    it allows the logging code to use more then one file descriptor. */
350 int
351 log_test_fd (int fd)
352 {
353   if (fileno (logstream?logstream:stderr) == fd)
354     return 1;
355   if (log_socket == fd)
356     return 1;
357   return 0;
358 }
359
360 int
361 log_get_fd ()
362 {
363   return fileno(logstream?logstream:stderr);
364 }
365
366 FILE *
367 log_get_stream ()
368 {
369   return logstream?logstream:stderr;
370 }
371
372
373 static void
374 do_logv (int level, const char *fmt, va_list arg_ptr)
375 {
376   if (!logstream)
377     logstream = stderr;
378
379   if (missing_lf && level != JNLIB_LOG_CONT)
380     putc('\n', logstream );
381   missing_lf = 0;
382
383   if (level != JNLIB_LOG_CONT)
384     { /* Note this does not work for multiple line logging as we would
385        * need to print to a buffer first */
386       if (with_time && !force_prefixes)
387         {
388           struct tm *tp;
389           time_t atime = time (NULL);
390           
391           tp = localtime (&atime);
392           fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
393                    1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
394                    tp->tm_hour, tp->tm_min, tp->tm_sec );
395         }
396       if (with_prefix || force_prefixes)
397         fputs (prefix_buffer, logstream);
398       if (with_pid || force_prefixes)
399         fprintf (logstream, "[%u]", (unsigned int)getpid ());
400       if (!with_time || force_prefixes)
401         putc (':', logstream);
402       /* A leading backspace suppresses the extra space so that we can
403          correctly output, programname, filename and linenumber. */
404       if (fmt && *fmt == '\b')
405         fmt++;
406       else
407         putc (' ', logstream);
408     }
409
410   switch (level)
411     {
412     case JNLIB_LOG_BEGIN: break;
413     case JNLIB_LOG_CONT: break;
414     case JNLIB_LOG_INFO: break;
415     case JNLIB_LOG_WARN: break;
416     case JNLIB_LOG_ERROR: break;
417     case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
418     case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
419     case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
420     default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
421     }
422
423
424   if (fmt)
425     {
426       vfprintf(logstream,fmt,arg_ptr) ;
427       if (*fmt && fmt[strlen(fmt)-1] != '\n')
428         missing_lf = 1;
429     }
430
431   if (level == JNLIB_LOG_FATAL)
432     exit(2);
433   if (level == JNLIB_LOG_BUG)
434     abort();
435 }
436
437 static void
438 do_log( int level, const char *fmt, ... )
439 {
440     va_list arg_ptr ;
441
442     va_start( arg_ptr, fmt ) ;
443     do_logv( level, fmt, arg_ptr );
444     va_end(arg_ptr);
445 }
446
447
448 void
449 log_logv (int level, const char *fmt, va_list arg_ptr)
450 {
451   do_logv (level, fmt, arg_ptr);
452 }
453
454 void
455 log_info( const char *fmt, ... )
456 {
457     va_list arg_ptr ;
458
459     va_start( arg_ptr, fmt ) ;
460     do_logv( JNLIB_LOG_INFO, fmt, arg_ptr );
461     va_end(arg_ptr);
462 }
463
464 void
465 log_error( const char *fmt, ... )
466 {
467     va_list arg_ptr ;
468
469     va_start( arg_ptr, fmt ) ;
470     do_logv( JNLIB_LOG_ERROR, fmt, arg_ptr );
471     va_end(arg_ptr);
472     /* protect against counter overflow */
473     if( errorcount < 30000 )
474         errorcount++;
475 }
476
477
478 void
479 log_fatal( const char *fmt, ... )
480 {
481     va_list arg_ptr ;
482
483     va_start( arg_ptr, fmt ) ;
484     do_logv( JNLIB_LOG_FATAL, fmt, arg_ptr );
485     va_end(arg_ptr);
486     abort(); /* never called, but it makes the compiler happy */
487 }
488
489 void
490 log_bug( const char *fmt, ... )
491 {
492     va_list arg_ptr ;
493
494     va_start( arg_ptr, fmt ) ;
495     do_logv( JNLIB_LOG_BUG, fmt, arg_ptr );
496     va_end(arg_ptr);
497     abort(); /* never called, but it makes the compiler happy */
498 }
499
500 void
501 log_debug( const char *fmt, ... )
502 {
503     va_list arg_ptr ;
504
505     va_start( arg_ptr, fmt ) ;
506     do_logv( JNLIB_LOG_DEBUG, fmt, arg_ptr );
507     va_end(arg_ptr);
508 }
509
510
511 void
512 log_printf (const char *fmt, ...)
513 {
514   va_list arg_ptr;
515
516   va_start (arg_ptr, fmt);
517   do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, fmt, arg_ptr);
518   va_end (arg_ptr);
519 }
520
521 /* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
522    dump, with TEXT just an empty string, print a trailing linefeed,
523    otherwise print an entire debug line. */
524 void
525 log_printhex (const char *text, const void *buffer, size_t length)
526 {
527   if (text && *text)
528     log_debug ("%s ", text);
529   if (length)
530     {
531       const unsigned char *p = buffer;
532       log_printf ("%02X", *p);
533       for (length--, p++; length--; p++)
534         log_printf (" %02X", *p);
535     }
536   if (text)
537     log_printf ("\n");
538 }
539
540
541 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
542 void
543 bug_at( const char *file, int line, const char *func )
544 {
545     do_log( JNLIB_LOG_BUG,
546              ("... this is a bug (%s:%d:%s)\n"), file, line, func );
547     abort(); /* never called, but it makes the compiler happy */
548 }
549 #else
550 void
551 bug_at( const char *file, int line )
552 {
553     do_log( JNLIB_LOG_BUG,
554              _("you found a bug ... (%s:%d)\n"), file, line);
555     abort(); /* never called, but it makes the compiler happy */
556 }
557 #endif
558