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