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