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