Imported Upstream version 2.1.0
[platform/upstream/gpg2.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 #ifdef HAVE_INET_PTON
261           void *addrbuf = NULL;
262 #endif /*HAVE_INET_PTON*/
263
264           addrstr = jnlib_malloc (strlen (name) + 1);
265           if (!addrstr)
266             addrlen = 0; /* This indicates an error.  */
267           else if (*name == '[')
268             {
269               /* Check for IPv6 literal address.  */
270               strcpy (addrstr, name+1);
271               p = strchr (addrstr, ']');
272               if (!p || p[1] != ':' || !parse_portno (p+2, &port))
273                 {
274                   jnlib_set_errno (EINVAL);
275                   addrlen = 0;
276                 }
277               else
278                 {
279                   *p = 0;
280 #ifdef WITH_IPV6
281                   af = AF_INET6;
282                   pf = PF_INET6;
283                   memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6);
284                   srvr_addr_in6.sin6_family = af;
285                   srvr_addr_in6.sin6_port = htons (port);
286 #ifdef HAVE_INET_PTON
287                   addrbuf = &srvr_addr_in6.sin6_addr;
288 #endif /*HAVE_INET_PTON*/
289                   srvr_addr = (struct sockaddr *)&srvr_addr_in6;
290                   addrlen = sizeof srvr_addr_in6;
291 #else
292                   jnlib_set_errno (EAFNOSUPPORT);
293                   addrlen = 0;
294 #endif
295                 }
296             }
297           else
298             {
299               /* Check for IPv4 literal address.  */
300               strcpy (addrstr, name);
301               p = strchr (addrstr, ':');
302               if (!p || !parse_portno (p+1, &port))
303                 {
304                   jnlib_set_errno (EINVAL);
305                   addrlen = 0;
306                 }
307               else
308                 {
309                   *p = 0;
310                   memset (&srvr_addr_in, 0, sizeof srvr_addr_in);
311                   srvr_addr_in.sin_family = af;
312                   srvr_addr_in.sin_port = htons (port);
313 #ifdef HAVE_INET_PTON
314                   addrbuf = &srvr_addr_in.sin_addr;
315 #endif /*HAVE_INET_PTON*/
316                   srvr_addr = (struct sockaddr *)&srvr_addr_in;
317                   addrlen = sizeof srvr_addr_in;
318                 }
319             }
320
321           if (addrlen)
322             {
323 #ifdef HAVE_INET_PTON
324               if (inet_pton (af, addrstr, addrbuf) != 1)
325                 addrlen = 0;
326 #else /*!HAVE_INET_PTON*/
327               /* We need to use the old function.  If we are here v6
328                  support isn't enabled anyway and thus we can do fine
329                  without.  Note that Windows has a compatible inet_pton
330                  function named inetPton, but only since Vista.  */
331               srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr);
332               if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE)
333                 addrlen = 0;
334 #endif /*!HAVE_INET_PTON*/
335             }
336
337           jnlib_free (addrstr);
338         }
339
340       cookie->fd = addrlen? socket (pf, SOCK_STREAM, 0) : -1;
341       if (cookie->fd == -1)
342         {
343           if (!cookie->quiet && !running_detached
344               && isatty (es_fileno (es_stderr)))
345             es_fprintf (es_stderr, "failed to create socket for logging: %s\n",
346                         strerror(errno));
347         }
348       else
349         {
350           if (connect (cookie->fd, srvr_addr, addrlen) == -1)
351             {
352               if (!cookie->quiet && !running_detached
353                   && isatty (es_fileno (es_stderr)))
354                 es_fprintf (es_stderr, "can't connect to '%s': %s\n",
355                             cookie->name, strerror(errno));
356               sock_close (cookie->fd);
357               cookie->fd = -1;
358             }
359         }
360
361       if (cookie->fd == -1)
362         {
363           if (!running_detached)
364             {
365               /* Due to all the problems with apps not running
366                  detached but being called with stderr closed or used
367                  for a different purposes, it does not make sense to
368                  switch to stderr.  We therefore disable it. */
369               if (!cookie->quiet)
370                 {
371                   /* fputs ("switching logging to stderr\n", stderr);*/
372                   cookie->quiet = 1;
373                 }
374               cookie->fd = -1; /*fileno (stderr);*/
375             }
376         }
377       else /* Connection has been established. */
378         {
379           cookie->quiet = 0;
380           cookie->is_socket = 1;
381         }
382     }
383
384   log_socket = cookie->fd;
385   if (cookie->fd != -1)
386     {
387 #ifdef HAVE_W32CE_SYSTEM
388       if (cookie->use_writefile)
389         {
390           DWORD nwritten;
391
392           WriteFile ((HANDLE)cookie->fd, buffer, size, &nwritten, NULL);
393           return (ssize_t)size; /* Okay.  */
394         }
395 #endif
396       if (!writen (cookie->fd, buffer, size, cookie->is_socket))
397         return (ssize_t)size; /* Okay. */
398     }
399
400   if (!running_detached && cookie->fd != -1
401       && isatty (es_fileno (es_stderr)))
402     {
403       if (*cookie->name)
404         es_fprintf (es_stderr, "error writing to '%s': %s\n",
405                     cookie->name, strerror(errno));
406       else
407         es_fprintf (es_stderr, "error writing to file descriptor %d: %s\n",
408                     cookie->fd, strerror(errno));
409     }
410   if (cookie->is_socket && cookie->fd != -1)
411     {
412       sock_close (cookie->fd);
413       cookie->fd = -1;
414       log_socket = -1;
415     }
416
417   return (ssize_t)size;
418 }
419
420
421 static int
422 fun_closer (void *cookie_arg)
423 {
424   struct fun_cookie_s *cookie = cookie_arg;
425
426   if (cookie->fd != -1 && cookie->fd != 2)
427     sock_close (cookie->fd);
428   jnlib_free (cookie);
429   log_socket = -1;
430   return 0;
431 }
432
433
434 /* Common function to either set the logging to a file or a file
435    descriptor. */
436 static void
437 set_file_fd (const char *name, int fd)
438 {
439   estream_t fp;
440   int want_socket;
441 #ifdef HAVE_W32CE_SYSTEM
442   int use_writefile = 0;
443 #endif
444   struct fun_cookie_s *cookie;
445
446   /* Close an open log stream.  */
447   if (logstream)
448     {
449       es_fclose (logstream);
450       logstream = NULL;
451     }
452
453   /* Figure out what kind of logging we want.  */
454   if (name && !strcmp (name, "-"))
455     {
456       name = NULL;
457       fd = es_fileno (es_stderr);
458     }
459
460   want_socket = 0;
461   if (name && !strncmp (name, "tcp://", 6) && name[6])
462     want_socket = 1;
463 #ifndef HAVE_W32_SYSTEM
464   else if (name && !strncmp (name, "socket://", 9) && name[9])
465     want_socket = 2;
466 #endif /*HAVE_W32_SYSTEM*/
467 #ifdef HAVE_W32CE_SYSTEM
468   else if (name && !strcmp (name, "GPG2:"))
469     {
470       HANDLE hd;
471
472       ActivateDevice (L"Drivers\\"GNUPG_NAME"_Log", 0);
473       /* Ignore a filename and write the debug output to the GPG2:
474          device.  */
475       hd = CreateFile (L"GPG2:", GENERIC_WRITE,
476                        FILE_SHARE_READ | FILE_SHARE_WRITE,
477                        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
478       fd = (hd == INVALID_HANDLE_VALUE)? -1 : (int)hd;
479       name = NULL;
480       force_prefixes = 1;
481       use_writefile = 1;
482     }
483 #endif /*HAVE_W32CE_SYSTEM*/
484
485   /* Setup a new stream.  */
486
487   /* The xmalloc below is justified because we can expect that this
488      function is called only during initialization and there is no
489      easy way out of this error condition.  */
490   cookie = jnlib_xmalloc (sizeof *cookie + (name? strlen (name):0));
491   strcpy (cookie->name, name? name:"");
492   cookie->quiet = 0;
493   cookie->is_socket = 0;
494   cookie->want_socket = want_socket;
495 #ifdef HAVE_W32CE_SYSTEM
496   cookie->use_writefile = use_writefile;
497 #endif
498   if (!name)
499     cookie->fd = fd;
500   else if (want_socket)
501     cookie->fd = -1;
502   else
503     {
504       do
505         cookie->fd = open (name, O_WRONLY|O_APPEND|O_CREAT,
506                            (S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH));
507       while (cookie->fd == -1 && errno == EINTR);
508     }
509   log_socket = cookie->fd;
510
511   {
512     es_cookie_io_functions_t io = { NULL };
513     io.func_write = fun_writer;
514     io.func_close = fun_closer;
515
516     fp = es_fopencookie (cookie, "w", io);
517   }
518
519   /* On error default to a stderr based estream.  */
520   if (!fp)
521     fp = es_stderr;
522
523   es_setvbuf (fp, NULL, _IOLBF, 0);
524
525   logstream = fp;
526
527   /* We always need to print the prefix and the pid for socket mode,
528      so that the server reading the socket can do something
529      meaningful. */
530   force_prefixes = want_socket;
531
532   missing_lf = 0;
533 }
534
535
536 /* Set the file to write log to.  The special names NULL and "-" may
537    be used to select stderr and names formatted like
538    "socket:///home/foo/mylogs" may be used to write the logging to the
539    socket "/home/foo/mylogs".  If the connection to the socket fails
540    or a write error is detected, the function writes to stderr and
541    tries the next time again to connect the socket.
542   */
543 void
544 log_set_file (const char *name)
545 {
546   set_file_fd (name? name: "-", -1);
547 }
548
549 void
550 log_set_fd (int fd)
551 {
552   set_file_fd (NULL, fd);
553 }
554
555
556 void
557 log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value))
558 {
559   get_pid_suffix_cb = cb;
560 }
561
562
563 void
564 log_set_prefix (const char *text, unsigned int flags)
565 {
566   if (text)
567     {
568       strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
569       prefix_buffer[sizeof (prefix_buffer)-1] = 0;
570     }
571
572   with_prefix = (flags & JNLIB_LOG_WITH_PREFIX);
573   with_time = (flags & JNLIB_LOG_WITH_TIME);
574   with_pid  = (flags & JNLIB_LOG_WITH_PID);
575   running_detached = (flags & JNLIB_LOG_RUN_DETACHED);
576 #ifdef HAVE_W32_SYSTEM
577   no_registry = (flags & JNLIB_LOG_NO_REGISTRY);
578 #endif
579 }
580
581
582 const char *
583 log_get_prefix (unsigned int *flags)
584 {
585   if (flags)
586     {
587       *flags = 0;
588       if (with_prefix)
589         *flags |= JNLIB_LOG_WITH_PREFIX;
590       if (with_time)
591         *flags |= JNLIB_LOG_WITH_TIME;
592       if (with_pid)
593         *flags |= JNLIB_LOG_WITH_PID;
594       if (running_detached)
595         *flags |= JNLIB_LOG_RUN_DETACHED;
596 #ifdef HAVE_W32_SYSTEM
597       if (no_registry)
598         *flags |= JNLIB_LOG_NO_REGISTRY;
599 #endif
600     }
601   return prefix_buffer;
602 }
603
604 /* This function returns true if the file descriptor FD is in use for
605    logging.  This is preferable over a test using log_get_fd in that
606    it allows the logging code to use more then one file descriptor.  */
607 int
608 log_test_fd (int fd)
609 {
610   if (logstream)
611     {
612       int tmp = es_fileno (logstream);
613       if ( tmp != -1 && tmp == fd)
614         return 1;
615     }
616   if (log_socket != -1 && log_socket == fd)
617     return 1;
618   return 0;
619 }
620
621 int
622 log_get_fd ()
623 {
624   return logstream? es_fileno(logstream) : -1;
625 }
626
627 estream_t
628 log_get_stream ()
629 {
630   if (!logstream)
631     {
632       log_set_file (NULL); /* Make sure a log stream has been set.  */
633       assert (logstream);
634     }
635   return logstream;
636 }
637
638 static void
639 do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
640 {
641   if (!logstream)
642     {
643 #ifdef HAVE_W32_SYSTEM
644       char *tmp;
645
646       tmp = (no_registry
647              ? NULL
648              : read_w32_registry_string (NULL, GNUPG_REGISTRY_DIR,
649                                          "DefaultLogFile"));
650       log_set_file (tmp && *tmp? tmp : NULL);
651       jnlib_free (tmp);
652 #else
653       log_set_file (NULL); /* Make sure a log stream has been set.  */
654 #endif
655       assert (logstream);
656     }
657
658   es_flockfile (logstream);
659   if (missing_lf && level != JNLIB_LOG_CONT)
660     es_putc_unlocked ('\n', logstream );
661   missing_lf = 0;
662
663   if (level != JNLIB_LOG_CONT)
664     { /* Note this does not work for multiple line logging as we would
665        * need to print to a buffer first */
666       if (with_time && !force_prefixes)
667         {
668           struct tm *tp;
669           time_t atime = time (NULL);
670
671           tp = localtime (&atime);
672           es_fprintf_unlocked (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
673                                1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
674                                tp->tm_hour, tp->tm_min, tp->tm_sec );
675         }
676       if (with_prefix || force_prefixes)
677         es_fputs_unlocked (prefix_buffer, logstream);
678       if (with_pid || force_prefixes)
679         {
680           unsigned long pidsuf;
681           int pidfmt;
682
683           if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf)))
684             es_fprintf_unlocked (logstream, pidfmt == 1? "[%u.%lu]":"[%u.%lx]",
685                                  (unsigned int)getpid (), pidsuf);
686           else
687             es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ());
688         }
689       if (!with_time || force_prefixes)
690         es_putc_unlocked (':', logstream);
691       /* A leading backspace suppresses the extra space so that we can
692          correctly output, programname, filename and linenumber. */
693       if (fmt && *fmt == '\b')
694         fmt++;
695       else
696         es_putc_unlocked (' ', logstream);
697     }
698
699   switch (level)
700     {
701     case JNLIB_LOG_BEGIN: break;
702     case JNLIB_LOG_CONT: break;
703     case JNLIB_LOG_INFO: break;
704     case JNLIB_LOG_WARN: break;
705     case JNLIB_LOG_ERROR: break;
706     case JNLIB_LOG_FATAL: es_fputs_unlocked ("Fatal: ",logstream ); break;
707     case JNLIB_LOG_BUG:   es_fputs_unlocked ("Ohhhh jeeee: ", logstream); break;
708     case JNLIB_LOG_DEBUG: es_fputs_unlocked ("DBG: ", logstream ); break;
709     default:
710       es_fprintf_unlocked (logstream,"[Unknown log level %d]: ", level);
711       break;
712     }
713
714   if (fmt)
715     {
716       if (ignore_arg_ptr)
717         es_fputs_unlocked (fmt, logstream);
718       else
719         es_vfprintf_unlocked (logstream, fmt, arg_ptr);
720       if (*fmt && fmt[strlen(fmt)-1] != '\n')
721         missing_lf = 1;
722     }
723
724   if (level == JNLIB_LOG_FATAL)
725     {
726       if (missing_lf)
727         es_putc_unlocked ('\n', logstream);
728       es_funlockfile (logstream);
729       exit (2);
730     }
731   else if (level == JNLIB_LOG_BUG)
732     {
733       if (missing_lf)
734         es_putc_unlocked ('\n', logstream );
735       es_funlockfile (logstream);
736       abort ();
737     }
738   else
739     es_funlockfile (logstream);
740 }
741
742
743 void
744 log_log (int level, const char *fmt, ...)
745 {
746   va_list arg_ptr ;
747
748   va_start (arg_ptr, fmt) ;
749   do_logv (level, 0, fmt, arg_ptr);
750   va_end (arg_ptr);
751 }
752
753
754 void
755 log_logv (int level, const char *fmt, va_list arg_ptr)
756 {
757   do_logv (level, 0, fmt, arg_ptr);
758 }
759
760
761 static void
762 do_log_ignore_arg (int level, const char *str, ...)
763 {
764   va_list arg_ptr;
765   va_start (arg_ptr, str);
766   do_logv (level, 1, str, arg_ptr);
767   va_end (arg_ptr);
768 }
769
770
771 void
772 log_string (int level, const char *string)
773 {
774   /* We need a dummy arg_ptr, but there is no portable way to create
775      one.  So we call the do_logv function through a variadic wrapper.
776      MB: Why not just use "%s"?  */
777   do_log_ignore_arg (level, string);
778 }
779
780
781 void
782 log_info (const char *fmt, ...)
783 {
784   va_list arg_ptr ;
785
786   va_start (arg_ptr, fmt);
787   do_logv (JNLIB_LOG_INFO, 0, fmt, arg_ptr);
788   va_end (arg_ptr);
789 }
790
791
792 void
793 log_error (const char *fmt, ...)
794 {
795   va_list arg_ptr ;
796
797   va_start (arg_ptr, fmt);
798   do_logv (JNLIB_LOG_ERROR, 0, fmt, arg_ptr);
799   va_end (arg_ptr);
800   /* Protect against counter overflow.  */
801   if (errorcount < 30000)
802     errorcount++;
803 }
804
805
806 void
807 log_fatal (const char *fmt, ...)
808 {
809   va_list arg_ptr ;
810
811   va_start (arg_ptr, fmt);
812   do_logv (JNLIB_LOG_FATAL, 0, fmt, arg_ptr);
813   va_end (arg_ptr);
814   abort (); /* Never called; just to make the compiler happy.  */
815 }
816
817
818 void
819 log_bug (const char *fmt, ...)
820 {
821   va_list arg_ptr ;
822
823   va_start (arg_ptr, fmt);
824   do_logv (JNLIB_LOG_BUG, 0, fmt, arg_ptr);
825   va_end (arg_ptr);
826   abort (); /* Never called; just to make the compiler happy.  */
827 }
828
829
830 void
831 log_debug (const char *fmt, ...)
832 {
833   va_list arg_ptr ;
834
835   va_start (arg_ptr, fmt);
836   do_logv (JNLIB_LOG_DEBUG, 0, fmt, arg_ptr);
837   va_end (arg_ptr);
838 }
839
840
841 void
842 log_printf (const char *fmt, ...)
843 {
844   va_list arg_ptr;
845
846   va_start (arg_ptr, fmt);
847   do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, 0, fmt, arg_ptr);
848   va_end (arg_ptr);
849 }
850
851
852 /* Flush the log - this is useful to make sure that the trailing
853    linefeed has been printed.  */
854 void
855 log_flush (void)
856 {
857   do_log_ignore_arg (JNLIB_LOG_CONT, NULL);
858 }
859
860
861 /* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
862    dump, with TEXT just an empty string, print a trailing linefeed,
863    otherwise print an entire debug line. */
864 void
865 log_printhex (const char *text, const void *buffer, size_t length)
866 {
867   if (text && *text)
868     log_debug ("%s ", text);
869   if (length)
870     {
871       const unsigned char *p = buffer;
872       log_printf ("%02X", *p);
873       for (length--, p++; length--; p++)
874         log_printf (" %02X", *p);
875     }
876   if (text)
877     log_printf ("\n");
878 }
879
880
881 /*
882 void
883 log_printcanon () {}
884 is found in sexputils.c
885 */
886
887 /*
888 void
889 log_printsexp () {}
890 is found in sexputils.c
891 */
892
893
894 void
895 log_clock (const char *string)
896 {
897 #if 0
898   static unsigned long long initial;
899   struct timespec tv;
900   unsigned long long now;
901
902   if (clock_gettime (CLOCK_REALTIME, &tv))
903     {
904       log_debug ("error getting the realtime clock value\n");
905       return;
906     }
907   now = tv.tv_sec * 1000000000ull;
908   now += tv.tv_nsec;
909
910   if (!initial)
911     initial = now;
912
913   log_debug ("[%6llu] %s", (now - initial)/1000, string);
914 #else
915   /* You need to link with -ltr to enable the above code.  */
916   log_debug ("[not enabled in the source] %s", string);
917 #endif
918 }
919
920
921 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
922 void
923 bug_at( const char *file, int line, const char *func )
924 {
925   log_log (JNLIB_LOG_BUG, ("... this is a bug (%s:%d:%s)\n"), file, line, func);
926   abort (); /* Never called; just to make the compiler happy.  */
927 }
928 #else
929 void
930 bug_at( const char *file, int line )
931 {
932   log_log (JNLIB_LOG_BUG, _("you found a bug ... (%s:%d)\n"), file, line);
933   abort (); /* Never called; just to make the compiler happy.  */
934 }
935 #endif