common: Improve a function's documentation and comments.
[gnupg.git] / common / logging.c
1 /* logging.c - Useful logging functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
3  *               2009, 2010 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 it
8  * under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * GnuPG is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * General Public License for more details.
26  *
27  * You should have received a copies of the GNU General Public License
28  * and the GNU Lesser General Public License along with this program;
29  * if not, see <http://www.gnu.org/licenses/>.
30  */
31
32
33 #include <config.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <stddef.h>
39 #include <errno.h>
40 #include <time.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #ifdef HAVE_W32_SYSTEM
44 # ifdef HAVE_WINSOCK2_H
45 #  include <winsock2.h>
46 # endif
47 # include <windows.h>
48 #else /*!HAVE_W32_SYSTEM*/
49 # include <sys/socket.h>
50 # include <sys/un.h>
51 # include <netinet/in.h>
52 # include <arpa/inet.h>
53 #endif /*!HAVE_W32_SYSTEM*/
54 #include <unistd.h>
55 #include <fcntl.h>
56 #include <assert.h>
57
58
59 #define GNUPG_COMMON_NEED_AFLOCAL 1
60 #include "util.h"
61 #include "i18n.h"
62 #include "common-defs.h"
63 #include "logging.h"
64
65 #ifdef HAVE_W32_SYSTEM
66 # define S_IRGRP S_IRUSR
67 # define S_IROTH S_IRUSR
68 # define S_IWGRP S_IWUSR
69 # define S_IWOTH S_IWUSR
70 #endif
71
72
73 #ifdef HAVE_W32CE_SYSTEM
74 # define isatty(a)  (0)
75 #endif
76
77 #undef WITH_IPV6
78 #if defined (AF_INET6) && defined(PF_INET) \
79     && defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON)
80 # define WITH_IPV6 1
81 #endif
82
83 #ifndef EAFNOSUPPORT
84 # define EAFNOSUPPORT EINVAL
85 #endif
86 #ifndef INADDR_NONE  /* Slowaris is missing that.  */
87 #define INADDR_NONE  ((unsigned long)(-1))
88 #endif /*INADDR_NONE*/
89
90 #ifdef HAVE_W32_SYSTEM
91 #define sock_close(a)  closesocket(a)
92 #else
93 #define sock_close(a)  close(a)
94 #endif
95
96
97 static estream_t logstream;
98 static int log_socket = -1;
99 static char prefix_buffer[80];
100 static int with_time;
101 static int with_prefix;
102 static int with_pid;
103 #ifdef HAVE_W32_SYSTEM
104 static int no_registry;
105 #endif
106 static int (*get_pid_suffix_cb)(unsigned long *r_value);
107 static int running_detached;
108 static int force_prefixes;
109
110 static int missing_lf;
111 static int errorcount;
112
113
114 int
115 log_get_errorcount (int clear)
116 {
117     int n = errorcount;
118     if( clear )
119         errorcount = 0;
120     return n;
121 }
122
123 void
124 log_inc_errorcount (void)
125 {
126    errorcount++;
127 }
128
129
130 /* The following 3 functions are used by es_fopencookie to write logs
131    to a socket.  */
132 struct fun_cookie_s
133 {
134   int fd;
135   int quiet;
136   int want_socket;
137   int is_socket;
138 #ifdef HAVE_W32CE_SYSTEM
139   int use_writefile;
140 #endif
141   char name[1];
142 };
143
144
145 /* Write NBYTES of BUFFER to file descriptor FD. */
146 static int
147 writen (int fd, const void *buffer, size_t nbytes, int is_socket)
148 {
149   const char *buf = buffer;
150   size_t nleft = nbytes;
151   int nwritten;
152 #ifndef HAVE_W32_SYSTEM
153   (void)is_socket; /* Not required.  */
154 #endif
155
156   while (nleft > 0)
157     {
158 #ifdef HAVE_W32_SYSTEM
159       if (is_socket)
160         nwritten = send (fd, buf, nleft, 0);
161       else
162 #endif
163         nwritten = write (fd, buf, nleft);
164
165       if (nwritten < 0 && errno == EINTR)
166         continue;
167       if (nwritten < 0)
168         return -1;
169       nleft -= nwritten;
170       buf = buf + nwritten;
171     }
172
173   return 0;
174 }
175
176
177 /* Returns true if STR represents a valid port number in decimal
178    notation and no garbage is following.  */
179 static int
180 parse_portno (const char *str, unsigned short *r_port)
181 {
182   unsigned int value;
183
184   for (value=0; *str && (*str >= '0' && *str <= '9'); str++)
185     {
186       value = value * 10 + (*str - '0');
187       if (value > 65535)
188         return 0;
189     }
190   if (*str || !value)
191     return 0;
192
193   *r_port = value;
194   return 1;
195 }
196
197
198 static gpgrt_ssize_t
199 fun_writer (void *cookie_arg, const void *buffer, size_t size)
200 {
201   struct fun_cookie_s *cookie = cookie_arg;
202
203   /* FIXME: Use only estream with a callback for socket writing.  This
204      avoids the ugly mix of fd and estream code.  */
205
206   /* Note that we always try to reconnect to the socket but print
207      error messages only the first time an error occurred.  If
208      RUNNING_DETACHED is set we don't fall back to stderr and even do
209      not print any error messages.  This is needed because detached
210      processes often close stderr and by writing to file descriptor 2
211      we might send the log message to a file not intended for logging
212      (e.g. a pipe or network connection). */
213   if (cookie->want_socket && cookie->fd == -1)
214     {
215 #ifdef WITH_IPV6
216       struct sockaddr_in6 srvr_addr_in6;
217 #endif
218       struct sockaddr_in srvr_addr_in;
219 #ifndef HAVE_W32_SYSTEM
220       struct sockaddr_un srvr_addr_un;
221 #endif
222       size_t addrlen;
223       struct sockaddr *srvr_addr = NULL;
224       unsigned short port = 0;
225       int af = AF_LOCAL;
226       int pf = PF_LOCAL;
227       const char *name = cookie->name;
228
229       /* Not yet open or meanwhile closed due to an error. */
230       cookie->is_socket = 0;
231
232       /* Check whether this is a TCP socket or a local socket.  */
233       if (!strncmp (name, "tcp://", 6) && name[6])
234         {
235           name += 6;
236           af = AF_INET;
237           pf = PF_INET;
238         }
239 #ifndef HAVE_W32_SYSTEM
240       else if (!strncmp (name, "socket://", 9) && name[9])
241         name += 9;
242 #endif
243
244       if (af == AF_LOCAL)
245         {
246 #ifdef HAVE_W32_SYSTEM
247           addrlen = 0;
248 #else
249           memset (&srvr_addr, 0, sizeof srvr_addr);
250           srvr_addr_un.sun_family = af;
251           strncpy (srvr_addr_un.sun_path,
252                    name, sizeof (srvr_addr_un.sun_path)-1);
253           srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
254           srvr_addr = (struct sockaddr *)&srvr_addr_un;
255           addrlen = SUN_LEN (&srvr_addr_un);
256 #endif
257         }
258       else
259         {
260           char *addrstr, *p;
261 #ifdef HAVE_INET_PTON
262           void *addrbuf = NULL;
263 #endif /*HAVE_INET_PTON*/
264
265           addrstr = xtrymalloc (strlen (name) + 1);
266           if (!addrstr)
267             addrlen = 0; /* This indicates an error.  */
268           else if (*name == '[')
269             {
270               /* Check for IPv6 literal address.  */
271               strcpy (addrstr, name+1);
272               p = strchr (addrstr, ']');
273               if (!p || p[1] != ':' || !parse_portno (p+2, &port))
274                 {
275                   gpg_err_set_errno (EINVAL);
276                   addrlen = 0;
277                 }
278               else
279                 {
280                   *p = 0;
281 #ifdef WITH_IPV6
282                   af = AF_INET6;
283                   pf = PF_INET6;
284                   memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
285                   srvr_addr_in6.sin6_family = af;
286                   srvr_addr_in6.sin6_port = htons (port);
287 #ifdef HAVE_INET_PTON
288                   addrbuf = &srvr_addr_in6.sin6_addr;
289 #endif /*HAVE_INET_PTON*/
290                   srvr_addr = (struct sockaddr *)&srvr_addr_in6;
291                   addrlen = sizeof srvr_addr_in6;
292 #else
293                   gpg_err_set_errno (EAFNOSUPPORT);
294                   addrlen = 0;
295 #endif
296                 }
297             }
298           else
299             {
300               /* Check for IPv4 literal address.  */
301               strcpy (addrstr, name);
302               p = strchr (addrstr, ':');
303               if (!p || !parse_portno (p+1, &port))
304                 {
305                   gpg_err_set_errno (EINVAL);
306                   addrlen = 0;
307                 }
308               else
309                 {
310                   *p = 0;
311                   memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
312                   srvr_addr_in.sin_family = af;
313                   srvr_addr_in.sin_port = htons (port);
314 #ifdef HAVE_INET_PTON
315                   addrbuf = &srvr_addr_in.sin_addr;
316 #endif /*HAVE_INET_PTON*/
317                   srvr_addr = (struct sockaddr *)&srvr_addr_in;
318                   addrlen = sizeof srvr_addr_in;
319                 }
320             }
321
322           if (addrlen)
323             {
324 #ifdef HAVE_INET_PTON
325               if (inet_pton (af, addrstr, addrbuf) != 1)
326                 addrlen = 0;
327 #else /*!HAVE_INET_PTON*/
328               /* We need to use the old function.  If we are here v6
329                  support isn't enabled anyway and thus we can do fine
330                  without.  Note that Windows has a compatible inet_pton
331                  function named inetPton, but only since Vista.  */
332               srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
333               if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
334                 addrlen = 0;
335 #endif /*!HAVE_INET_PTON*/
336             }
337
338           xfree (addrstr);
339         }
340
341       cookie->fd = addrlen? socket (pf, SOCK_STREAM, 0) : -1;
342       if (cookie->fd == -1)
343         {
344           if (!cookie->quiet && !running_detached
345               && isatty (es_fileno (es_stderr)))
346             es_fprintf (es_stderr, "failed to create socket for logging: %s\n",
347                         strerror(errno));
348         }
349       else
350         {
351           if (connect (cookie->fd, srvr_addr, addrlen) == -1)
352             {
353               if (!cookie->quiet && !running_detached
354                   && isatty (es_fileno (es_stderr)))
355                 es_fprintf (es_stderr, "can't connect to '%s': %s\n",
356                             cookie->name, strerror(errno));
357               sock_close (cookie->fd);
358               cookie->fd = -1;
359             }
360         }
361
362       if (cookie->fd == -1)
363         {
364           if (!running_detached)
365             {
366               /* Due to all the problems with apps not running
367                  detached but being called with stderr closed or used
368                  for a different purposes, it does not make sense to
369                  switch to stderr.  We therefore disable it. */
370               if (!cookie->quiet)
371                 {
372                   /* fputs ("switching logging to stderr\n", stderr);*/
373                   cookie->quiet = 1;
374                 }
375               cookie->fd = -1; /*fileno (stderr);*/
376             }
377         }
378       else /* Connection has been established. */
379         {
380           cookie->quiet = 0;
381           cookie->is_socket = 1;
382         }
383     }
384
385   log_socket = cookie->fd;
386   if (cookie->fd != -1)
387     {
388 #ifdef HAVE_W32CE_SYSTEM
389       if (cookie->use_writefile)
390         {
391           DWORD nwritten;
392
393           WriteFile ((HANDLE)cookie->fd, buffer, size, &nwritten, NULL);
394           return (gpgrt_ssize_t)size; /* Okay.  */
395         }
396 #endif
397       if (!writen (cookie->fd, buffer, size, cookie->is_socket))
398         return (gpgrt_ssize_t)size; /* Okay. */
399     }
400
401   if (!running_detached && cookie->fd != -1
402       && isatty (es_fileno (es_stderr)))
403     {
404       if (*cookie->name)
405         es_fprintf (es_stderr, "error writing to '%s': %s\n",
406                     cookie->name, strerror(errno));
407       else
408         es_fprintf (es_stderr, "error writing to file descriptor %d: %s\n",
409                     cookie->fd, strerror(errno));
410     }
411   if (cookie->is_socket && cookie->fd != -1)
412     {
413       sock_close (cookie->fd);
414       cookie->fd = -1;
415       log_socket = -1;
416     }
417
418   return (gpgrt_ssize_t)size;
419 }
420
421
422 static int
423 fun_closer (void *cookie_arg)
424 {
425   struct fun_cookie_s *cookie = cookie_arg;
426
427   if (cookie->fd != -1 && cookie->fd != 2)
428     sock_close (cookie->fd);
429   xfree (cookie);
430   log_socket = -1;
431   return 0;
432 }
433
434
435 /* Common function to either set the logging to a file or a file
436    descriptor. */
437 static void
438 set_file_fd (const char *name, int fd)
439 {
440   estream_t fp;
441   int want_socket;
442 #ifdef HAVE_W32CE_SYSTEM
443   int use_writefile = 0;
444 #endif
445   struct fun_cookie_s *cookie;
446
447   /* Close an open log stream.  */
448   if (logstream)
449     {
450       es_fclose (logstream);
451       logstream = NULL;
452     }
453
454   /* Figure out what kind of logging we want.  */
455   if (name && !strcmp (name, "-"))
456     {
457       name = NULL;
458       fd = es_fileno (es_stderr);
459     }
460
461   want_socket = 0;
462   if (name && !strncmp (name, "tcp://", 6) && name[6])
463     want_socket = 1;
464 #ifndef HAVE_W32_SYSTEM
465   else if (name && !strncmp (name, "socket://", 9) && name[9])
466     want_socket = 2;
467 #endif /*HAVE_W32_SYSTEM*/
468 #ifdef HAVE_W32CE_SYSTEM
469   else if (name && !strcmp (name, "GPG2:"))
470     {
471       HANDLE hd;
472
473       ActivateDevice (L"Drivers\\"GNUPG_NAME"_Log", 0);
474       /* Ignore a filename and write the debug output to the GPG2:
475          device.  */
476       hd = CreateFile (L"GPG2:", GENERIC_WRITE,
477                        FILE_SHARE_READ | FILE_SHARE_WRITE,
478                        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
479       fd = (hd == INVALID_HANDLE_VALUE)? -1 : (int)hd;
480       name = NULL;
481       force_prefixes = 1;
482       use_writefile = 1;
483     }
484 #endif /*HAVE_W32CE_SYSTEM*/
485
486   /* Setup a new stream.  */
487
488   /* The xmalloc below is justified because we can expect that this
489      function is called only during initialization and there is no
490      easy way out of this error condition.  */
491   cookie = xmalloc (sizeof *cookie + (name? strlen (name):0));
492   strcpy (cookie->name, name? name:"");
493   cookie->quiet = 0;
494   cookie->is_socket = 0;
495   cookie->want_socket = want_socket;
496 #ifdef HAVE_W32CE_SYSTEM
497   cookie->use_writefile = use_writefile;
498 #endif
499   if (!name)
500     cookie->fd = fd;
501   else if (want_socket)
502     cookie->fd = -1;
503   else
504     {
505       do
506         cookie->fd = open (name, O_WRONLY|O_APPEND|O_CREAT,
507                            (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH));
508       while (cookie->fd == -1 && errno == EINTR);
509     }
510   log_socket = cookie->fd;
511
512   {
513     es_cookie_io_functions_t io = { NULL };
514     io.func_write = fun_writer;
515     io.func_close = fun_closer;
516
517     fp = es_fopencookie (cookie, "w", io);
518   }
519
520   /* On error default to a stderr based estream.  */
521   if (!fp)
522     fp = es_stderr;
523
524   es_setvbuf (fp, NULL, _IOLBF, 0);
525
526   logstream = fp;
527
528   /* We always need to print the prefix and the pid for socket mode,
529      so that the server reading the socket can do something
530      meaningful. */
531   force_prefixes = want_socket;
532
533   missing_lf = 0;
534 }
535
536
537 /* Set the file to write log to.  The special names NULL and "-" may
538    be used to select stderr and names formatted like
539    "socket:///home/foo/mylogs" may be used to write the logging to the
540    socket "/home/foo/mylogs".  If the connection to the socket fails
541    or a write error is detected, the function writes to stderr and
542    tries the next time again to connect the socket.
543   */
544 void
545 log_set_file (const char *name)
546 {
547   set_file_fd (name? name: "-", -1);
548 }
549
550 void
551 log_set_fd (int fd)
552 {
553   set_file_fd (NULL, fd);
554 }
555
556
557 void
558 log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value))
559 {
560   get_pid_suffix_cb = cb;
561 }
562
563
564 void
565 log_set_prefix (const char *text, unsigned int flags)
566 {
567   if (text)
568     {
569       strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
570       prefix_buffer[sizeof (prefix_buffer)-1] = 0;
571     }
572
573   with_prefix = (flags & GPGRT_LOG_WITH_PREFIX);
574   with_time = (flags & GPGRT_LOG_WITH_TIME);
575   with_pid  = (flags & GPGRT_LOG_WITH_PID);
576   running_detached = (flags & GPGRT_LOG_RUN_DETACHED);
577 #ifdef HAVE_W32_SYSTEM
578   no_registry = (flags & GPGRT_LOG_NO_REGISTRY);
579 #endif
580 }
581
582
583 const char *
584 log_get_prefix (unsigned int *flags)
585 {
586   if (flags)
587     {
588       *flags = 0;
589       if (with_prefix)
590         *flags |= GPGRT_LOG_WITH_PREFIX;
591       if (with_time)
592         *flags |= GPGRT_LOG_WITH_TIME;
593       if (with_pid)
594         *flags |= GPGRT_LOG_WITH_PID;
595       if (running_detached)
596         *flags |= GPGRT_LOG_RUN_DETACHED;
597 #ifdef HAVE_W32_SYSTEM
598       if (no_registry)
599         *flags |= GPGRT_LOG_NO_REGISTRY;
600 #endif
601     }
602   return prefix_buffer;
603 }
604
605 /* This function returns true if the file descriptor FD is in use for
606    logging.  This is preferable over a test using log_get_fd in that
607    it allows the logging code to use more then one file descriptor.  */
608 int
609 log_test_fd (int fd)
610 {
611   if (logstream)
612     {
613       int tmp = es_fileno (logstream);
614       if ( tmp != -1 && tmp == fd)
615         return 1;
616     }
617   if (log_socket != -1 && log_socket == fd)
618     return 1;
619   return 0;
620 }
621
622 int
623 log_get_fd ()
624 {
625   return logstream? es_fileno(logstream) : -1;
626 }
627
628 estream_t
629 log_get_stream ()
630 {
631   if (!logstream)
632     {
633       log_set_file (NULL); /* Make sure a log stream has been set.  */
634       assert (logstream);
635     }
636   return logstream;
637 }
638
639 static void
640 do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
641 {
642   if (!logstream)
643     {
644 #ifdef HAVE_W32_SYSTEM
645       char *tmp;
646
647       tmp = (no_registry
648              ? NULL
649              : read_w32_registry_string (NULL, GNUPG_REGISTRY_DIR,
650                                          "DefaultLogFile"));
651       log_set_file (tmp && *tmp? tmp : NULL);
652       xfree (tmp);
653 #else
654       log_set_file (NULL); /* Make sure a log stream has been set.  */
655 #endif
656       assert (logstream);
657     }
658
659   es_flockfile (logstream);
660   if (missing_lf && level != GPGRT_LOG_CONT)
661     es_putc_unlocked ('\n', logstream );
662   missing_lf = 0;
663
664   if (level != GPGRT_LOG_CONT)
665     { /* Note this does not work for multiple line logging as we would
666        * need to print to a buffer first */
667       if (with_time && !force_prefixes)
668         {
669           struct tm *tp;
670           time_t atime = time (NULL);
671
672           tp = localtime (&atime);
673           es_fprintf_unlocked (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
674                                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
675                                tp->tm_hour, tp->tm_min, tp->tm_sec );
676         }
677       if (with_prefix || force_prefixes)
678         es_fputs_unlocked (prefix_buffer, logstream);
679       if (with_pid || force_prefixes)
680         {
681           unsigned long pidsuf;
682           int pidfmt;
683
684           if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf)))
685             es_fprintf_unlocked (logstream, pidfmt == 1? "[%u.%lu]":"[%u.%lx]",
686                                  (unsigned int)getpid (), pidsuf);
687           else
688             es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ());
689         }
690       if (!with_time || force_prefixes)
691         es_putc_unlocked (':', logstream);
692       /* A leading backspace suppresses the extra space so that we can
693          correctly output, programname, filename and linenumber. */
694       if (fmt && *fmt == '\b')
695         fmt++;
696       else
697         es_putc_unlocked (' ', logstream);
698     }
699
700   switch (level)
701     {
702     case GPGRT_LOG_BEGIN: break;
703     case GPGRT_LOG_CONT: break;
704     case GPGRT_LOG_INFO: break;
705     case GPGRT_LOG_WARN: break;
706     case GPGRT_LOG_ERROR: break;
707     case GPGRT_LOG_FATAL: es_fputs_unlocked ("Fatal: ",logstream ); break;
708     case GPGRT_LOG_BUG:   es_fputs_unlocked ("Ohhhh jeeee: ", logstream); break;
709     case GPGRT_LOG_DEBUG: es_fputs_unlocked ("DBG: ", logstream ); break;
710     default:
711       es_fprintf_unlocked (logstream,"[Unknown log level %d]: ", level);
712       break;
713     }
714
715   if (fmt)
716     {
717       if (ignore_arg_ptr)
718         es_fputs_unlocked (fmt, logstream);
719       else
720         es_vfprintf_unlocked (logstream, fmt, arg_ptr);
721       if (*fmt && fmt[strlen(fmt)-1] != '\n')
722         missing_lf = 1;
723     }
724
725   if (level == GPGRT_LOG_FATAL)
726     {
727       if (missing_lf)
728         es_putc_unlocked ('\n', logstream);
729       es_funlockfile (logstream);
730       exit (2);
731     }
732   else if (level == GPGRT_LOG_BUG)
733     {
734       if (missing_lf)
735         es_putc_unlocked ('\n', logstream );
736       es_funlockfile (logstream);
737       abort ();
738     }
739   else
740     es_funlockfile (logstream);
741 }
742
743
744 void
745 log_log (int level, const char *fmt, ...)
746 {
747   va_list arg_ptr ;
748
749   va_start (arg_ptr, fmt) ;
750   do_logv (level, 0, fmt, arg_ptr);
751   va_end (arg_ptr);
752 }
753
754
755 void
756 log_logv (int level, const char *fmt, va_list arg_ptr)
757 {
758   do_logv (level, 0, fmt, arg_ptr);
759 }
760
761
762 static void
763 do_log_ignore_arg (int level, const char *str, ...)
764 {
765   va_list arg_ptr;
766   va_start (arg_ptr, str);
767   do_logv (level, 1, str, arg_ptr);
768   va_end (arg_ptr);
769 }
770
771
772 void
773 log_string (int level, const char *string)
774 {
775   /* We need a dummy arg_ptr, but there is no portable way to create
776      one.  So we call the do_logv function through a variadic wrapper.
777      MB: Why not just use "%s"?  */
778   do_log_ignore_arg (level, string);
779 }
780
781
782 void
783 log_info (const char *fmt, ...)
784 {
785   va_list arg_ptr ;
786
787   va_start (arg_ptr, fmt);
788   do_logv (GPGRT_LOG_INFO, 0, fmt, arg_ptr);
789   va_end (arg_ptr);
790 }
791
792
793 void
794 log_error (const char *fmt, ...)
795 {
796   va_list arg_ptr ;
797
798   va_start (arg_ptr, fmt);
799   do_logv (GPGRT_LOG_ERROR, 0, fmt, arg_ptr);
800   va_end (arg_ptr);
801   /* Protect against counter overflow.  */
802   if (errorcount < 30000)
803     errorcount++;
804 }
805
806
807 void
808 log_fatal (const char *fmt, ...)
809 {
810   va_list arg_ptr ;
811
812   va_start (arg_ptr, fmt);
813   do_logv (GPGRT_LOG_FATAL, 0, fmt, arg_ptr);
814   va_end (arg_ptr);
815   abort (); /* Never called; just to make the compiler happy.  */
816 }
817
818
819 void
820 log_bug (const char *fmt, ...)
821 {
822   va_list arg_ptr ;
823
824   va_start (arg_ptr, fmt);
825   do_logv (GPGRT_LOG_BUG, 0, fmt, arg_ptr);
826   va_end (arg_ptr);
827   abort (); /* Never called; just to make the compiler happy.  */
828 }
829
830
831 void
832 log_debug (const char *fmt, ...)
833 {
834   va_list arg_ptr ;
835
836   va_start (arg_ptr, fmt);
837   do_logv (GPGRT_LOG_DEBUG, 0, fmt, arg_ptr);
838   va_end (arg_ptr);
839 }
840
841
842 void
843 log_printf (const char *fmt, ...)
844 {
845   va_list arg_ptr;
846
847   va_start (arg_ptr, fmt);
848   do_logv (fmt ? GPGRT_LOG_CONT : GPGRT_LOG_BEGIN, 0, fmt, arg_ptr);
849   va_end (arg_ptr);
850 }
851
852
853 /* Flush the log - this is useful to make sure that the trailing
854    linefeed has been printed.  */
855 void
856 log_flush (void)
857 {
858   do_log_ignore_arg (GPGRT_LOG_CONT, NULL);
859 }
860
861
862 /* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
863    dump, with TEXT just an empty string, print a trailing linefeed,
864    otherwise print an entire debug line. */
865 void
866 log_printhex (const char *text, const void *buffer, size_t length)
867 {
868   if (text && *text)
869     log_debug ("%s ", text);
870   if (length)
871     {
872       const unsigned char *p = buffer;
873       log_printf ("%02X", *p);
874       for (length--, p++; length--; p++)
875         log_printf (" %02X", *p);
876     }
877   if (text)
878     log_printf ("\n");
879 }
880
881
882 /*
883 void
884 log_printcanon () {}
885 is found in sexputils.c
886 */
887
888 /*
889 void
890 log_printsexp () {}
891 is found in sexputils.c
892 */
893
894
895 void
896 log_clock (const char *string)
897 {
898 #if 0
899   static unsigned long long initial;
900   struct timespec tv;
901   unsigned long long now;
902
903   if (clock_gettime (CLOCK_REALTIME, &tv))
904     {
905       log_debug ("error getting the realtime clock value\n");
906       return;
907     }
908   now = tv.tv_sec * 1000000000ull;
909   now += tv.tv_nsec;
910
911   if (!initial)
912     initial = now;
913
914   log_debug ("[%6llu] %s", (now - initial)/1000, string);
915 #else
916   /* You need to link with -ltr to enable the above code.  */
917   log_debug ("[not enabled in the source] %s", string);
918 #endif
919 }
920
921
922 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
923 void
924 bug_at( const char *file, int line, const char *func )
925 {
926   log_log (GPGRT_LOG_BUG, ("... this is a bug (%s:%d:%s)\n"), file, line, func);
927   abort (); /* Never called; just to make the compiler happy.  */
928 }
929 #else
930 void
931 bug_at( const char *file, int line )
932 {
933   log_log (GPGRT_LOG_BUG, _("you found a bug ... (%s:%d)\n"), file, line);
934   abort (); /* Never called; just to make the compiler happy.  */
935 }
936 #endif