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