Add help strings for all commands.
[gnupg.git] / jnlib / logging.c
blob028697b78fb30744564f14571fcfed8970265d23
1 /* logging.c - Useful logging functions
2 * Copyright (C) 1998, 1999, 2000, 2001, 2003,
3 * 2004, 2005, 2006, 2009 Free Software Foundation, Inc.
5 * This file is part of JNLIB.
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.
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.
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/>.
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>
41 #define JNLIB_NEED_LOG_LOGV 1
42 #define JNLIB_NEED_AFLOCAL 1
43 #include "libjnlib-config.h"
44 #include "logging.h"
46 #if defined (HAVE_FOPENCOOKIE) || defined (HAVE_FUNOPEN)
47 #define USE_FUNWRITER 1
48 #endif
50 #ifdef HAVE_FOPENCOOKIE
51 typedef ssize_t my_funopen_hook_ret_t;
52 typedef size_t my_funopen_hook_size_t;
53 #else
54 typedef int my_funopen_hook_ret_t;
55 typedef int my_funopen_hook_size_t;
56 #endif
59 static FILE *logstream;
60 static int log_socket = -1;
61 static char prefix_buffer[80];
62 static int with_time;
63 static int with_prefix;
64 static int with_pid;
65 static unsigned long (*get_tid_callback)(void);
66 static int running_detached;
67 static int force_prefixes;
69 static int missing_lf;
70 static int errorcount;
73 int
74 log_get_errorcount (int clear)
76 int n = errorcount;
77 if( clear )
78 errorcount = 0;
79 return n;
82 void
83 log_inc_errorcount (void)
85 errorcount++;
89 /* The follwing 3 functions are used by funopen to write logs to a
90 socket. */
91 #ifdef USE_FUNWRITER
92 struct fun_cookie_s {
93 int fd;
94 int quiet;
95 int want_socket;
96 int is_socket;
97 char name[1];
100 /* Write NBYTES of BUFFER to file descriptor FD. */
101 static int
102 writen (int fd, const void *buffer, size_t nbytes)
104 const char *buf = buffer;
105 size_t nleft = nbytes;
106 int nwritten;
108 while (nleft > 0)
110 nwritten = write (fd, buf, nleft);
111 if (nwritten < 0 && errno == EINTR)
112 continue;
113 if (nwritten < 0)
114 return -1;
115 nleft -= nwritten;
116 buf = buf + nwritten;
119 return 0;
123 static my_funopen_hook_ret_t
124 fun_writer (void *cookie_arg, const char *buffer, my_funopen_hook_size_t size)
126 struct fun_cookie_s *cookie = cookie_arg;
128 /* Note that we always try to reconnect to the socket but print
129 error messages only the first time an error occured. If
130 RUNNING_DETACHED is set we don't fall back to stderr and even do
131 not print any error messages. This is needed because detached
132 processes often close stderr and by writing to file descriptor 2
133 we might send the log message to a file not intended for logging
134 (e.g. a pipe or network connection). */
135 if (cookie->want_socket && cookie->fd == -1)
137 /* Not yet open or meanwhile closed due to an error. */
138 cookie->is_socket = 0;
139 cookie->fd = socket (PF_LOCAL, SOCK_STREAM, 0);
140 if (cookie->fd == -1)
142 if (!cookie->quiet && !running_detached
143 && isatty (fileno (stderr)))
144 fprintf (stderr, "failed to create socket for logging: %s\n",
145 strerror(errno));
147 else
149 struct sockaddr_un addr;
150 size_t addrlen;
152 memset (&addr, 0, sizeof addr);
153 addr.sun_family = PF_LOCAL;
154 strncpy (addr.sun_path, cookie->name, sizeof (addr.sun_path)-1);
155 addr.sun_path[sizeof (addr.sun_path)-1] = 0;
156 addrlen = SUN_LEN (&addr);
158 if (connect (cookie->fd, (struct sockaddr *) &addr, addrlen) == -1)
160 if (!cookie->quiet && !running_detached
161 && isatty (fileno (stderr)))
162 fprintf (stderr, "can't connect to `%s': %s\n",
163 cookie->name, strerror(errno));
164 close (cookie->fd);
165 cookie->fd = -1;
169 if (cookie->fd == -1)
171 if (!running_detached)
173 /* Due to all the problems with apps not running
174 detached but being called with stderr closed or
175 used for a different purposes, it does not make
176 sense to switch to stderr. We therefore disable it. */
177 if (!cookie->quiet)
179 /* fputs ("switching logging to stderr\n", stderr);*/
180 cookie->quiet = 1;
182 cookie->fd = -1; /*fileno (stderr);*/
185 else /* Connection has been established. */
187 cookie->quiet = 0;
188 cookie->is_socket = 1;
192 log_socket = cookie->fd;
193 if (cookie->fd != -1 && !writen (cookie->fd, buffer, size))
194 return (my_funopen_hook_ret_t)size; /* Okay. */
196 if (!running_detached && cookie->fd != -1
197 && isatty (fileno (stderr)))
199 if (*cookie->name)
200 fprintf (stderr, "error writing to `%s': %s\n",
201 cookie->name, strerror(errno));
202 else
203 fprintf (stderr, "error writing to file descriptor %d: %s\n",
204 cookie->fd, strerror(errno));
206 if (cookie->is_socket && cookie->fd != -1)
208 close (cookie->fd);
209 cookie->fd = -1;
210 log_socket = -1;
213 return (my_funopen_hook_ret_t)size;
216 static int
217 fun_closer (void *cookie_arg)
219 struct fun_cookie_s *cookie = cookie_arg;
221 if (cookie->fd != -1 && cookie->fd != 2)
222 close (cookie->fd);
223 jnlib_free (cookie);
224 log_socket = -1;
225 return 0;
227 #endif /*USE_FUNWRITER*/
231 /* Common function to either set the logging to a file or a file
232 descriptor. */
233 static void
234 set_file_fd (const char *name, int fd)
236 FILE *fp;
237 int want_socket;
238 #ifdef USE_FUNWRITER
239 struct fun_cookie_s *cookie;
240 #endif
242 /* Close an open log stream. */
243 if (logstream)
245 if (logstream != stderr && logstream != stdout)
246 fclose (logstream);
247 logstream = NULL;
250 /* Figure out what kind of logging we want. */
251 if (name && !strcmp (name, "-"))
253 name = NULL;
254 fd = fileno (stderr);
257 if (name)
259 want_socket = (!strncmp (name, "socket://", 9) && name[9]);
260 if (want_socket)
261 name += 9;
263 else
265 want_socket = 0;
268 /* Setup a new stream. */
269 #ifdef USE_FUNWRITER
270 /* The xmalloc below is justified because we can expect that this
271 function is called only during initialization and there is no
272 easy way out of this error condition. */
273 cookie = jnlib_xmalloc (sizeof *cookie + (name? strlen (name):0));
274 strcpy (cookie->name, name? name:"");
275 cookie->quiet = 0;
276 cookie->is_socket = 0;
277 cookie->want_socket = want_socket;
278 if (!name)
279 cookie->fd = fd;
280 else if (want_socket)
281 cookie->fd = -1;
282 else
285 cookie->fd = open (name, O_WRONLY|O_APPEND|O_CREAT,
286 (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH));
287 while (cookie->fd == -1 && errno == EINTR);
289 log_socket = cookie->fd;
291 #ifdef HAVE_FOPENCOOKIE
293 cookie_io_functions_t io = { NULL };
294 io.write = fun_writer;
295 io.close = fun_closer;
297 fp = fopencookie (cookie, "w", io);
299 #else /*!HAVE_FOPENCOOKIE*/
300 fp = funopen (cookie, NULL, fun_writer, NULL, fun_closer);
301 #endif /*!HAVE_FOPENCOOKIE*/
303 #else /*!USE_FUNWRITER*/
305 /* The system does not feature custom streams. Thus fallback to
306 plain stdio. */
307 if (want_socket)
309 fprintf (stderr, "system does not support logging to a socket - "
310 "using stderr\n");
311 fp = stderr;
313 else if (name)
314 fp = fopen (name, "a");
315 else if (fd == 1)
316 fp = stdout;
317 else if (fd == 2)
318 fp = stderr;
319 else
320 fp = fdopen (fd, "a");
322 log_socket = -1;
324 #endif /*!USE_FUNWRITER*/
326 /* On error default to stderr. */
327 if (!fp)
329 if (name)
330 fprintf (stderr, "failed to open log file `%s': %s\n",
331 name, strerror(errno));
332 else
333 fprintf (stderr, "failed to fdopen file descriptor %d: %s\n",
334 fd, strerror(errno));
335 /* We need to make sure that there is a log stream. We use stderr. */
336 fp = stderr;
338 else
339 setvbuf (fp, NULL, _IOLBF, 0);
341 logstream = fp;
343 /* We always need to print the prefix and the pid for socket mode,
344 so that the server reading the socket can do something
345 meaningful. */
346 force_prefixes = want_socket;
348 missing_lf = 0;
352 /* Set the file to write log to. The special names NULL and "-" may
353 be used to select stderr and names formatted like
354 "socket:///home/foo/mylogs" may be used to write the logging to the
355 socket "/home/foo/mylogs". If the connection to the socket fails
356 or a write error is detected, the function writes to stderr and
357 tries the next time again to connect the socket.
359 void
360 log_set_file (const char *name)
362 set_file_fd (name? name: "-", -1);
365 void
366 log_set_fd (int fd)
368 set_file_fd (NULL, fd);
372 void
373 log_set_get_tid_callback (unsigned long (*cb)(void))
375 get_tid_callback = cb;
379 void
380 log_set_prefix (const char *text, unsigned int flags)
382 if (text)
384 strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
385 prefix_buffer[sizeof (prefix_buffer)-1] = 0;
388 with_prefix = (flags & JNLIB_LOG_WITH_PREFIX);
389 with_time = (flags & JNLIB_LOG_WITH_TIME);
390 with_pid = (flags & JNLIB_LOG_WITH_PID);
391 running_detached = (flags & JNLIB_LOG_RUN_DETACHED);
395 const char *
396 log_get_prefix (unsigned int *flags)
398 if (flags)
400 *flags = 0;
401 if (with_prefix)
402 *flags |= JNLIB_LOG_WITH_PREFIX;
403 if (with_time)
404 *flags |= JNLIB_LOG_WITH_TIME;
405 if (with_pid)
406 *flags |= JNLIB_LOG_WITH_PID;
407 if (running_detached)
408 *flags |= JNLIB_LOG_RUN_DETACHED;
410 return prefix_buffer;
413 /* This function returns true if the file descriptor FD is in use for
414 logging. This is preferable over a test using log_get_fd in that
415 it allows the logging code to use more then one file descriptor. */
417 log_test_fd (int fd)
419 if (logstream)
421 int tmp = fileno (logstream);
422 if ( tmp != -1 && tmp == fd)
423 return 1;
425 if (log_socket != -1 && log_socket == fd)
426 return 1;
427 return 0;
431 log_get_fd ()
433 return fileno(logstream?logstream:stderr);
436 FILE *
437 log_get_stream ()
439 /* FIXME: We should not return stderr here but initialize the log
440 stream properly. This might break more things than using stderr,
441 though */
442 return logstream?logstream:stderr;
445 static void
446 do_logv (int level, const char *fmt, va_list arg_ptr)
448 if (!logstream)
450 log_set_file (NULL); /* Make sure a log stream has been set. */
451 assert (logstream);
454 if (missing_lf && level != JNLIB_LOG_CONT)
455 putc('\n', logstream );
456 missing_lf = 0;
458 if (level != JNLIB_LOG_CONT)
459 { /* Note this does not work for multiple line logging as we would
460 * need to print to a buffer first */
461 if (with_time && !force_prefixes)
463 struct tm *tp;
464 time_t atime = time (NULL);
466 tp = localtime (&atime);
467 fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
468 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
469 tp->tm_hour, tp->tm_min, tp->tm_sec );
471 if (with_prefix || force_prefixes)
472 fputs (prefix_buffer, logstream);
473 if (with_pid || force_prefixes)
475 if (get_tid_callback)
476 fprintf (logstream, "[%u.%lx]",
477 (unsigned int)getpid (), get_tid_callback ());
478 else
479 fprintf (logstream, "[%u]", (unsigned int)getpid ());
481 if (!with_time || force_prefixes)
482 putc (':', logstream);
483 /* A leading backspace suppresses the extra space so that we can
484 correctly output, programname, filename and linenumber. */
485 if (fmt && *fmt == '\b')
486 fmt++;
487 else
488 putc (' ', logstream);
491 switch (level)
493 case JNLIB_LOG_BEGIN: break;
494 case JNLIB_LOG_CONT: break;
495 case JNLIB_LOG_INFO: break;
496 case JNLIB_LOG_WARN: break;
497 case JNLIB_LOG_ERROR: break;
498 case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
499 case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
500 case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
501 default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
505 if (fmt)
507 vfprintf(logstream,fmt,arg_ptr) ;
508 if (*fmt && fmt[strlen(fmt)-1] != '\n')
509 missing_lf = 1;
510 #ifdef HAVE_W32_SYSTEM
511 else
512 fflush (logstream);
513 #endif
516 if (level == JNLIB_LOG_FATAL)
518 if (missing_lf)
519 putc('\n', logstream );
520 exit(2);
522 if (level == JNLIB_LOG_BUG)
524 if (missing_lf)
525 putc('\n', logstream );
526 abort();
530 static void
531 do_log( int level, const char *fmt, ... )
533 va_list arg_ptr ;
535 va_start( arg_ptr, fmt ) ;
536 do_logv( level, fmt, arg_ptr );
537 va_end(arg_ptr);
541 void
542 log_logv (int level, const char *fmt, va_list arg_ptr)
544 do_logv (level, fmt, arg_ptr);
547 void
548 log_info( const char *fmt, ... )
550 va_list arg_ptr ;
552 va_start( arg_ptr, fmt ) ;
553 do_logv( JNLIB_LOG_INFO, fmt, arg_ptr );
554 va_end(arg_ptr);
557 void
558 log_error( const char *fmt, ... )
560 va_list arg_ptr ;
562 va_start( arg_ptr, fmt ) ;
563 do_logv( JNLIB_LOG_ERROR, fmt, arg_ptr );
564 va_end(arg_ptr);
565 /* protect against counter overflow */
566 if( errorcount < 30000 )
567 errorcount++;
571 void
572 log_fatal( const char *fmt, ... )
574 va_list arg_ptr ;
576 va_start( arg_ptr, fmt ) ;
577 do_logv( JNLIB_LOG_FATAL, fmt, arg_ptr );
578 va_end(arg_ptr);
579 abort(); /* never called, but it makes the compiler happy */
582 void
583 log_bug( const char *fmt, ... )
585 va_list arg_ptr ;
587 va_start( arg_ptr, fmt ) ;
588 do_logv( JNLIB_LOG_BUG, fmt, arg_ptr );
589 va_end(arg_ptr);
590 abort(); /* never called, but it makes the compiler happy */
593 void
594 log_debug( const char *fmt, ... )
596 va_list arg_ptr ;
598 va_start( arg_ptr, fmt ) ;
599 do_logv( JNLIB_LOG_DEBUG, fmt, arg_ptr );
600 va_end(arg_ptr);
604 void
605 log_printf (const char *fmt, ...)
607 va_list arg_ptr;
609 va_start (arg_ptr, fmt);
610 do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, fmt, arg_ptr);
611 va_end (arg_ptr);
614 /* Print a hexdump of BUFFER. With TEXT of NULL print just the raw
615 dump, with TEXT just an empty string, print a trailing linefeed,
616 otherwise print an entire debug line. */
617 void
618 log_printhex (const char *text, const void *buffer, size_t length)
620 if (text && *text)
621 log_debug ("%s ", text);
622 if (length)
624 const unsigned char *p = buffer;
625 log_printf ("%02X", *p);
626 for (length--, p++; length--; p++)
627 log_printf (" %02X", *p);
629 if (text)
630 log_printf ("\n");
634 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
635 void
636 bug_at( const char *file, int line, const char *func )
638 do_log( JNLIB_LOG_BUG,
639 ("... this is a bug (%s:%d:%s)\n"), file, line, func );
640 abort(); /* never called, but it makes the compiler happy */
642 #else
643 void
644 bug_at( const char *file, int line )
646 do_log( JNLIB_LOG_BUG,
647 _("you found a bug ... (%s:%d)\n"), file, line);
648 abort(); /* never called, but it makes the compiler happy */
650 #endif