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