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