/src/libgpg-error-1.49/src/logging.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* logging.c - Useful logging functions |
2 | | * Copyright (C) 1998-2001, 2003-2006, 2009-2010, |
3 | | * 2017 Free Software Foundation, Inc. |
4 | | * Copyright (C) 1998-1999, 2001-2006, 2008-2017 Werner Koch |
5 | | * |
6 | | * This file is part of Libgpg-error. |
7 | | * |
8 | | * Libgpg-error is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public License |
10 | | * as published by the Free Software Foundation; either version 2.1 of |
11 | | * the License, or (at your option) any later version. |
12 | | * |
13 | | * Libgpg-error is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public |
19 | | * License along with this program; if not, see <https://www.gnu.org/licenses/>. |
20 | | * SPDX-License-Identifier: LGPL-2.1+ |
21 | | * |
22 | | * This file was originally a part of GnuPG. |
23 | | */ |
24 | | |
25 | | #include <config.h> |
26 | | |
27 | | #include <stdlib.h> |
28 | | #include <stdio.h> |
29 | | #include <string.h> |
30 | | #include <stdarg.h> |
31 | | #include <stddef.h> |
32 | | #include <errno.h> |
33 | | #include <time.h> |
34 | | #include <sys/types.h> |
35 | | #include <sys/stat.h> |
36 | | #ifdef HAVE_W32_SYSTEM |
37 | | # ifdef HAVE_WINSOCK2_H |
38 | | # include <winsock2.h> |
39 | | # endif |
40 | | # include <windows.h> |
41 | | #else /*!HAVE_W32_SYSTEM*/ |
42 | | # include <sys/socket.h> |
43 | | # include <sys/un.h> |
44 | | # include <netinet/in.h> |
45 | | # include <arpa/inet.h> |
46 | | #endif /*!HAVE_W32_SYSTEM*/ |
47 | | #include <unistd.h> |
48 | | #include <fcntl.h> |
49 | | /* #include <execinfo.h> */ |
50 | | |
51 | | #define _GPGRT_NEED_AFLOCAL 1 |
52 | | #include "gpgrt-int.h" |
53 | | |
54 | | |
55 | | #ifdef HAVE_W32_SYSTEM |
56 | | # ifndef S_IRWXG |
57 | | # define S_IRGRP S_IRUSR |
58 | | # define S_IWGRP S_IWUSR |
59 | | # endif |
60 | | # ifndef S_IRWXO |
61 | | # define S_IROTH S_IRUSR |
62 | | # define S_IWOTH S_IWUSR |
63 | | # endif |
64 | | #endif |
65 | | |
66 | | |
67 | | #undef WITH_IPV6 |
68 | | #if defined (AF_INET6) && defined(PF_INET) \ |
69 | | && defined (INET6_ADDRSTRLEN) && defined(HAVE_INET_PTON) |
70 | | # define WITH_IPV6 1 |
71 | | #endif |
72 | | |
73 | | #ifndef EAFNOSUPPORT |
74 | | # define EAFNOSUPPORT EINVAL |
75 | | #endif |
76 | | #ifndef INADDR_NONE /* Slowaris is missing that. */ |
77 | | #define INADDR_NONE ((unsigned long)(-1)) |
78 | | #endif /*INADDR_NONE*/ |
79 | | |
80 | | #ifdef HAVE_W32_SYSTEM |
81 | | #define sock_close(a) closesocket(a) |
82 | | #else |
83 | 0 | #define sock_close(a) close(a) |
84 | | #endif |
85 | | |
86 | | |
87 | | static estream_t logstream; |
88 | | static int log_socket = -1; |
89 | | static char prefix_buffer[80]; |
90 | | static int with_time; |
91 | | static int with_prefix; |
92 | | static int with_pid; |
93 | | #ifdef HAVE_W32_SYSTEM |
94 | | static int no_registry; |
95 | | #endif |
96 | | static int (*get_pid_suffix_cb)(unsigned long *r_value); |
97 | | static const char * (*socket_dir_cb)(void); |
98 | | static int running_detached; |
99 | | static int force_prefixes; |
100 | | |
101 | | static int missing_lf; |
102 | | static int errorcount; |
103 | | |
104 | | /* The list of registered functions to be called after logging. */ |
105 | | struct post_log_func_item_s; |
106 | | typedef struct post_log_func_item_s *post_log_func_item_t; |
107 | | struct post_log_func_item_s |
108 | | { |
109 | | post_log_func_item_t next; |
110 | | void (*func) (int); |
111 | | }; |
112 | | static post_log_func_item_t post_log_func_list; |
113 | | |
114 | | |
115 | | |
116 | | |
117 | | /* An object to convey data to the fmt_string_filter. */ |
118 | | struct fmt_string_filter_s |
119 | | { |
120 | | char *last_result; |
121 | | }; |
122 | | |
123 | | |
124 | | |
125 | | /* Get the error count as maintained by the log fucntions. With CLEAR |
126 | | * set reset the counter. */ |
127 | | int |
128 | | _gpgrt_get_errorcount (int clear) |
129 | 0 | { |
130 | 0 | int n = errorcount; |
131 | 0 | if (clear) |
132 | 0 | errorcount = 0; |
133 | 0 | return n; |
134 | 0 | } |
135 | | |
136 | | |
137 | | /* Increment the error count as maintained by the log functions. */ |
138 | | void |
139 | | _gpgrt_inc_errorcount (void) |
140 | 0 | { |
141 | | /* Protect against counter overflow. */ |
142 | 0 | if (errorcount < 30000) |
143 | 0 | errorcount++; |
144 | 0 | } |
145 | | |
146 | | |
147 | | /* The following 3 functions are used by _gpgrt_fopencookie to write logs |
148 | | to a socket. */ |
149 | | struct fun_cookie_s |
150 | | { |
151 | | int fd; |
152 | | int quiet; |
153 | | int want_socket; |
154 | | int is_socket; |
155 | | char name[1]; |
156 | | }; |
157 | | |
158 | | |
159 | | /* Write NBYTES of BUFFER to file descriptor FD. */ |
160 | | static int |
161 | | writen (int fd, const void *buffer, size_t nbytes, int is_socket) |
162 | 0 | { |
163 | 0 | const char *buf = buffer; |
164 | 0 | size_t nleft = nbytes; |
165 | 0 | int nwritten; |
166 | 0 | #ifndef HAVE_W32_SYSTEM |
167 | 0 | (void)is_socket; /* Not required. */ |
168 | 0 | #endif |
169 | |
|
170 | 0 | while (nleft > 0) |
171 | 0 | { |
172 | | #ifdef HAVE_W32_SYSTEM |
173 | | if (is_socket) |
174 | | nwritten = send (fd, buf, nleft, 0); |
175 | | else |
176 | | #endif |
177 | 0 | nwritten = write (fd, buf, nleft); |
178 | |
|
179 | 0 | if (nwritten < 0 && errno == EINTR) |
180 | 0 | continue; |
181 | 0 | if (nwritten < 0) |
182 | 0 | return -1; |
183 | 0 | nleft -= nwritten; |
184 | 0 | buf = buf + nwritten; |
185 | 0 | } |
186 | | |
187 | 0 | return 0; |
188 | 0 | } |
189 | | |
190 | | |
191 | | /* Returns true if STR represents a valid port number in decimal |
192 | | notation and no garbage is following. */ |
193 | | static int |
194 | | parse_portno (const char *str, unsigned short *r_port) |
195 | 0 | { |
196 | 0 | unsigned int value; |
197 | |
|
198 | 0 | for (value=0; *str && (*str >= '0' && *str <= '9'); str++) |
199 | 0 | { |
200 | 0 | value = value * 10 + (*str - '0'); |
201 | 0 | if (value > 65535) |
202 | 0 | return 0; |
203 | 0 | } |
204 | 0 | if (*str || !value) |
205 | 0 | return 0; |
206 | | |
207 | 0 | *r_port = value; |
208 | 0 | return 1; |
209 | 0 | } |
210 | | |
211 | | |
212 | | static gpgrt_ssize_t |
213 | | fun_writer (void *cookie_arg, const void *buffer, size_t size) |
214 | 0 | { |
215 | 0 | struct fun_cookie_s *cookie = cookie_arg; |
216 | | |
217 | | /* Note that we always try to reconnect to the socket but print |
218 | | error messages only the first time an error occurred. If |
219 | | RUNNING_DETACHED is set we don't fall back to stderr and even do |
220 | | not print any error messages. This is needed because detached |
221 | | processes often close stderr and by writing to file descriptor 2 |
222 | | we might send the log message to a file not intended for logging |
223 | | (e.g. a pipe or network connection). */ |
224 | 0 | if (cookie->want_socket && cookie->fd == -1) |
225 | 0 | { |
226 | 0 | #ifdef WITH_IPV6 |
227 | 0 | struct sockaddr_in6 srvr_addr_in6; |
228 | 0 | #endif |
229 | 0 | struct sockaddr_in srvr_addr_in; |
230 | 0 | #ifndef HAVE_W32_SYSTEM |
231 | 0 | struct sockaddr_un srvr_addr_un; |
232 | 0 | #endif |
233 | 0 | const char *name_for_err = ""; |
234 | 0 | size_t addrlen; |
235 | 0 | struct sockaddr *srvr_addr = NULL; |
236 | 0 | unsigned short port = 0; |
237 | 0 | int af = AF_LOCAL; |
238 | 0 | int pf = PF_LOCAL; |
239 | 0 | const char *name = cookie->name; |
240 | | |
241 | | /* Not yet open or meanwhile closed due to an error. */ |
242 | 0 | cookie->is_socket = 0; |
243 | | |
244 | | /* Check whether this is a TCP socket or a local socket. */ |
245 | 0 | if (!strncmp (name, "tcp://", 6) && name[6]) |
246 | 0 | { |
247 | 0 | name += 6; |
248 | 0 | af = AF_INET; |
249 | 0 | pf = PF_INET; |
250 | 0 | } |
251 | 0 | #ifndef HAVE_W32_SYSTEM |
252 | 0 | else if (!strncmp (name, "socket://", 9)) |
253 | 0 | name += 9; |
254 | 0 | #endif |
255 | |
|
256 | 0 | if (af == AF_LOCAL) |
257 | 0 | { |
258 | 0 | addrlen = 0; |
259 | 0 | #ifndef HAVE_W32_SYSTEM |
260 | 0 | memset (&srvr_addr, 0, sizeof srvr_addr); |
261 | 0 | srvr_addr_un.sun_family = af; |
262 | 0 | if (!*name) |
263 | 0 | { |
264 | 0 | if (socket_dir_cb && (name = socket_dir_cb ()) && *name |
265 | 0 | && strlen (name) + 7 < sizeof (srvr_addr_un.sun_path)-1) |
266 | 0 | { |
267 | 0 | strncpy (srvr_addr_un.sun_path, |
268 | 0 | name, sizeof (srvr_addr_un.sun_path)-1); |
269 | 0 | strcat (srvr_addr_un.sun_path, "/S.log"); |
270 | 0 | srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0; |
271 | 0 | srvr_addr = (struct sockaddr *)&srvr_addr_un; |
272 | 0 | addrlen = SUN_LEN (&srvr_addr_un); |
273 | 0 | name_for_err = srvr_addr_un.sun_path; |
274 | 0 | } |
275 | 0 | } |
276 | 0 | else |
277 | 0 | { |
278 | 0 | if (strlen (name) < sizeof (srvr_addr_un.sun_path)-1) |
279 | 0 | { |
280 | 0 | strncpy (srvr_addr_un.sun_path, |
281 | 0 | name, sizeof (srvr_addr_un.sun_path)-1); |
282 | 0 | srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0; |
283 | 0 | srvr_addr = (struct sockaddr *)&srvr_addr_un; |
284 | 0 | addrlen = SUN_LEN (&srvr_addr_un); |
285 | 0 | } |
286 | 0 | } |
287 | 0 | #endif /*!HAVE_W32SYSTEM*/ |
288 | 0 | } |
289 | 0 | else |
290 | 0 | { |
291 | 0 | char *addrstr, *p; |
292 | 0 | #ifdef HAVE_INET_PTON |
293 | 0 | void *addrbuf = NULL; |
294 | 0 | #endif /*HAVE_INET_PTON*/ |
295 | |
|
296 | 0 | addrstr = _gpgrt_malloc (strlen (name) + 1); |
297 | 0 | if (!addrstr) |
298 | 0 | addrlen = 0; /* This indicates an error. */ |
299 | 0 | else if (*name == '[') |
300 | 0 | { |
301 | | /* Check for IPv6 literal address. */ |
302 | 0 | strcpy (addrstr, name+1); |
303 | 0 | p = strchr (addrstr, ']'); |
304 | 0 | if (!p || p[1] != ':' || !parse_portno (p+2, &port)) |
305 | 0 | { |
306 | 0 | _gpg_err_set_errno (EINVAL); |
307 | 0 | addrlen = 0; |
308 | 0 | } |
309 | 0 | else |
310 | 0 | { |
311 | 0 | *p = 0; |
312 | 0 | #ifdef WITH_IPV6 |
313 | 0 | af = AF_INET6; |
314 | 0 | pf = PF_INET6; |
315 | 0 | memset (&srvr_addr_in6, 0, sizeof srvr_addr_in6); |
316 | 0 | srvr_addr_in6.sin6_family = af; |
317 | 0 | srvr_addr_in6.sin6_port = htons (port); |
318 | 0 | #ifdef HAVE_INET_PTON |
319 | 0 | addrbuf = &srvr_addr_in6.sin6_addr; |
320 | 0 | #endif /*HAVE_INET_PTON*/ |
321 | 0 | srvr_addr = (struct sockaddr *)&srvr_addr_in6; |
322 | 0 | addrlen = sizeof srvr_addr_in6; |
323 | | #else |
324 | | _gpg_err_set_errno (EAFNOSUPPORT); |
325 | | addrlen = 0; |
326 | | #endif |
327 | 0 | } |
328 | 0 | } |
329 | 0 | else |
330 | 0 | { |
331 | | /* Check for IPv4 literal address. */ |
332 | 0 | strcpy (addrstr, name); |
333 | 0 | p = strchr (addrstr, ':'); |
334 | 0 | if (!p || !parse_portno (p+1, &port)) |
335 | 0 | { |
336 | 0 | _gpg_err_set_errno (EINVAL); |
337 | 0 | addrlen = 0; |
338 | 0 | } |
339 | 0 | else |
340 | 0 | { |
341 | 0 | *p = 0; |
342 | 0 | memset (&srvr_addr_in, 0, sizeof srvr_addr_in); |
343 | 0 | srvr_addr_in.sin_family = af; |
344 | 0 | srvr_addr_in.sin_port = htons (port); |
345 | 0 | #ifdef HAVE_INET_PTON |
346 | 0 | addrbuf = &srvr_addr_in.sin_addr; |
347 | 0 | #endif /*HAVE_INET_PTON*/ |
348 | 0 | srvr_addr = (struct sockaddr *)&srvr_addr_in; |
349 | 0 | addrlen = sizeof srvr_addr_in; |
350 | 0 | } |
351 | 0 | } |
352 | |
|
353 | 0 | if (addrlen) |
354 | 0 | { |
355 | 0 | #ifdef HAVE_INET_PTON |
356 | 0 | if (inet_pton (af, addrstr, addrbuf) != 1) |
357 | 0 | addrlen = 0; |
358 | | #else /*!HAVE_INET_PTON*/ |
359 | | /* We need to use the old function. If we are here v6 |
360 | | support isn't enabled anyway and thus we can do fine |
361 | | without. Note that Windows has a compatible inet_pton |
362 | | function named inetPton, but only since Vista. */ |
363 | | srvr_addr_in.sin_addr.s_addr = inet_addr (addrstr); |
364 | | if (srvr_addr_in.sin_addr.s_addr == INADDR_NONE) |
365 | | addrlen = 0; |
366 | | #endif /*!HAVE_INET_PTON*/ |
367 | 0 | } |
368 | |
|
369 | 0 | _gpgrt_free (addrstr); |
370 | 0 | } |
371 | |
|
372 | 0 | cookie->fd = addrlen? socket (pf, SOCK_STREAM, 0) : -1; |
373 | 0 | if (cookie->fd == -1) |
374 | 0 | { |
375 | 0 | if (!cookie->quiet && !running_detached |
376 | 0 | && isatty (_gpgrt_fileno (es_stderr))) |
377 | 0 | _gpgrt_fprintf (es_stderr, |
378 | 0 | "failed to create socket for logging: %s\n", |
379 | 0 | strerror (errno)); |
380 | 0 | } |
381 | 0 | else |
382 | 0 | { |
383 | 0 | if (connect (cookie->fd, srvr_addr, addrlen) == -1) |
384 | 0 | { |
385 | 0 | if (!cookie->quiet && !running_detached |
386 | 0 | && isatty (_gpgrt_fileno (es_stderr))) |
387 | 0 | _gpgrt_fprintf (es_stderr, "can't connect to '%s%s': %s\n", |
388 | 0 | cookie->name, name_for_err, strerror(errno)); |
389 | 0 | sock_close (cookie->fd); |
390 | 0 | cookie->fd = -1; |
391 | 0 | } |
392 | 0 | } |
393 | |
|
394 | 0 | if (cookie->fd == -1) |
395 | 0 | { |
396 | 0 | if (!running_detached) |
397 | 0 | { |
398 | | /* Due to all the problems with apps not running |
399 | | detached but being called with stderr closed or used |
400 | | for a different purposes, it does not make sense to |
401 | | switch to stderr. We therefore disable it. */ |
402 | 0 | if (!cookie->quiet) |
403 | 0 | { |
404 | | /* fputs ("switching logging to stderr\n", stderr);*/ |
405 | 0 | cookie->quiet = 1; |
406 | 0 | } |
407 | 0 | cookie->fd = -1; /*fileno (stderr);*/ |
408 | 0 | } |
409 | 0 | } |
410 | 0 | else /* Connection has been established. */ |
411 | 0 | { |
412 | 0 | cookie->quiet = 0; |
413 | 0 | cookie->is_socket = 1; |
414 | 0 | } |
415 | 0 | } |
416 | |
|
417 | 0 | log_socket = cookie->fd; |
418 | 0 | if (cookie->fd != -1) |
419 | 0 | { |
420 | 0 | if (!writen (cookie->fd, buffer, size, cookie->is_socket)) |
421 | 0 | return (gpgrt_ssize_t)size; /* Okay. */ |
422 | 0 | } |
423 | | |
424 | 0 | if (!running_detached && cookie->fd != -1 |
425 | 0 | && isatty (_gpgrt_fileno (es_stderr))) |
426 | 0 | { |
427 | 0 | if (*cookie->name) |
428 | 0 | _gpgrt_fprintf (es_stderr, "error writing to '%s': %s\n", |
429 | 0 | cookie->name, strerror(errno)); |
430 | 0 | else |
431 | 0 | _gpgrt_fprintf (es_stderr, "error writing to file descriptor %d: %s\n", |
432 | 0 | cookie->fd, strerror(errno)); |
433 | 0 | } |
434 | 0 | if (cookie->is_socket && cookie->fd != -1) |
435 | 0 | { |
436 | 0 | sock_close (cookie->fd); |
437 | 0 | cookie->fd = -1; |
438 | 0 | log_socket = -1; |
439 | 0 | } |
440 | |
|
441 | 0 | return (gpgrt_ssize_t)size; |
442 | 0 | } |
443 | | |
444 | | |
445 | | static int |
446 | | fun_closer (void *cookie_arg) |
447 | 0 | { |
448 | 0 | struct fun_cookie_s *cookie = cookie_arg; |
449 | |
|
450 | 0 | if (cookie->fd != -1 && cookie->fd != 2) |
451 | 0 | sock_close (cookie->fd); |
452 | 0 | _gpgrt_free (cookie); |
453 | 0 | log_socket = -1; |
454 | 0 | return 0; |
455 | 0 | } |
456 | | |
457 | | |
458 | | /* Common function to either set the logging to a file or a file |
459 | | descriptor. */ |
460 | | static void |
461 | | set_file_fd (const char *name, int fd, estream_t stream) |
462 | 0 | { |
463 | 0 | estream_t fp; |
464 | 0 | int want_socket = 0; |
465 | 0 | struct fun_cookie_s *cookie; |
466 | | |
467 | | /* Close an open log stream. */ |
468 | 0 | if (logstream) |
469 | 0 | { |
470 | 0 | if (logstream != es_stderr) |
471 | 0 | _gpgrt_fclose (logstream); |
472 | 0 | logstream = NULL; |
473 | 0 | } |
474 | |
|
475 | 0 | if (stream) |
476 | 0 | { |
477 | | /* We don't use a cookie to log directly to a stream. */ |
478 | 0 | fp = stream; |
479 | 0 | goto leave; |
480 | 0 | } |
481 | | |
482 | | /* Figure out what kind of logging we want. */ |
483 | 0 | if (name && !strcmp (name, "-")) |
484 | 0 | { |
485 | 0 | fp = es_stderr; |
486 | 0 | goto leave; |
487 | 0 | } |
488 | 0 | else if (name && !strncmp (name, "tcp://", 6) && name[6]) |
489 | 0 | want_socket = 1; |
490 | 0 | #ifndef HAVE_W32_SYSTEM |
491 | 0 | else if (name && !strncmp (name, "socket://", 9)) |
492 | 0 | want_socket = 2; |
493 | 0 | #endif /*HAVE_W32_SYSTEM*/ |
494 | | |
495 | | /* Setup a new stream. */ |
496 | | |
497 | 0 | if (!name) |
498 | 0 | fp = _gpgrt_fdopen (fd, "w"); |
499 | 0 | else if (!want_socket) |
500 | 0 | fp = _gpgrt_fopen (name, "a"); |
501 | 0 | else |
502 | 0 | { |
503 | 0 | es_cookie_io_functions_t io = { NULL }; |
504 | |
|
505 | 0 | cookie = _gpgrt_malloc (sizeof *cookie + (name? strlen (name):0)); |
506 | 0 | if (!cookie) |
507 | 0 | return; /* oops */ |
508 | 0 | strcpy (cookie->name, name? name:""); |
509 | 0 | cookie->quiet = 0; |
510 | 0 | cookie->is_socket = 0; |
511 | 0 | cookie->want_socket = want_socket; |
512 | 0 | cookie->fd = -1; |
513 | 0 | log_socket = cookie->fd; |
514 | |
|
515 | 0 | io.func_write = fun_writer; |
516 | 0 | io.func_close = fun_closer; |
517 | |
|
518 | 0 | fp = _gpgrt_fopencookie (cookie, "w", io); |
519 | 0 | } |
520 | | |
521 | | /* On error default to a stderr based estream. */ |
522 | 0 | if (!fp) |
523 | 0 | fp = es_stderr; |
524 | |
|
525 | 0 | leave: |
526 | 0 | _gpgrt_setvbuf (fp, NULL, _IOLBF, 0); |
527 | |
|
528 | 0 | logstream = fp; |
529 | | |
530 | | /* We always need to print the prefix and the pid for socket mode, |
531 | | so that the server reading the socket can do something |
532 | | meaningful. */ |
533 | 0 | force_prefixes = want_socket; |
534 | |
|
535 | 0 | missing_lf = 0; |
536 | 0 | } |
537 | | |
538 | | |
539 | | /* Set the file to write log to. The special names NULL and "-" may |
540 | | * be used to select stderr and names formatted like |
541 | | * "socket:///home/foo/mylogs" may be used to write the logging to the |
542 | | * socket "/home/foo/mylogs". If the connection to the socket fails |
543 | | * or a write error is detected, the function writes to stderr and |
544 | | * tries the next time again to connect the socket. Calling this |
545 | | * function with (NULL, NULL, -1) sets the default sink. |
546 | | * Warning: This function is not thread-safe. |
547 | | */ |
548 | | void |
549 | | _gpgrt_log_set_sink (const char *name, estream_t stream, int fd) |
550 | 0 | { |
551 | 0 | if (name && !stream && fd == -1) |
552 | 0 | set_file_fd (name, -1, NULL); |
553 | 0 | else if (!name && !stream && fd != -1) |
554 | 0 | { |
555 | 0 | if (!_gpgrt_fd_valid_p (fd)) |
556 | 0 | _gpgrt_log_fatal ("gpgrt_log_set_sink: fd is invalid: %s\n", |
557 | 0 | strerror (errno)); |
558 | 0 | set_file_fd (NULL, fd, NULL); |
559 | 0 | } |
560 | 0 | else if (!name && stream && fd == -1) |
561 | 0 | { |
562 | 0 | set_file_fd (NULL, -1, stream); |
563 | 0 | } |
564 | 0 | else /* default */ |
565 | 0 | set_file_fd ("-", -1, NULL); |
566 | 0 | } |
567 | | |
568 | | |
569 | | /* Set a function to retrieve the directory name of a socket if |
570 | | * only "socket://" has been given to log_set_file. |
571 | | * Warning: This function is not thread-safe. */ |
572 | | void |
573 | | _gpgrt_log_set_socket_dir_cb (const char *(*fnc)(void)) |
574 | 0 | { |
575 | 0 | socket_dir_cb = fnc; |
576 | 0 | } |
577 | | |
578 | | |
579 | | /* Warning: This function is not thread-safe. */ |
580 | | void |
581 | | _gpgrt_log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value)) |
582 | 0 | { |
583 | 0 | get_pid_suffix_cb = cb; |
584 | 0 | } |
585 | | |
586 | | |
587 | | /* Warning: Changing TEXT is not thread-safe. Changing only flags |
588 | | * might be thread-safe. */ |
589 | | void |
590 | | _gpgrt_log_set_prefix (const char *text, unsigned int flags) |
591 | 0 | { |
592 | 0 | if (text) |
593 | 0 | { |
594 | 0 | strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1); |
595 | 0 | prefix_buffer[sizeof (prefix_buffer)-1] = 0; |
596 | 0 | } |
597 | |
|
598 | 0 | with_prefix = (flags & GPGRT_LOG_WITH_PREFIX); |
599 | 0 | with_time = (flags & GPGRT_LOG_WITH_TIME); |
600 | 0 | with_pid = (flags & GPGRT_LOG_WITH_PID); |
601 | 0 | running_detached = (flags & GPGRT_LOG_RUN_DETACHED); |
602 | | #ifdef HAVE_W32_SYSTEM |
603 | | no_registry = (flags & GPGRT_LOG_NO_REGISTRY); |
604 | | #endif |
605 | 0 | } |
606 | | |
607 | | |
608 | | const char * |
609 | | _gpgrt_log_get_prefix (unsigned int *flags) |
610 | 0 | { |
611 | 0 | if (flags) |
612 | 0 | { |
613 | 0 | *flags = 0; |
614 | 0 | if (with_prefix) |
615 | 0 | *flags |= GPGRT_LOG_WITH_PREFIX; |
616 | 0 | if (with_time) |
617 | 0 | *flags |= GPGRT_LOG_WITH_TIME; |
618 | 0 | if (with_pid) |
619 | 0 | *flags |= GPGRT_LOG_WITH_PID; |
620 | 0 | if (running_detached) |
621 | 0 | *flags |= GPGRT_LOG_RUN_DETACHED; |
622 | | #ifdef HAVE_W32_SYSTEM |
623 | | if (no_registry) |
624 | | *flags |= GPGRT_LOG_NO_REGISTRY; |
625 | | #endif |
626 | 0 | } |
627 | 0 | return prefix_buffer; |
628 | 0 | } |
629 | | |
630 | | /* This function returns true if the file descriptor FD is in use for |
631 | | * logging. This is preferable over a test using log_get_fd in that |
632 | | * it allows the logging code to use more then one file descriptor. */ |
633 | | int |
634 | | _gpgrt_log_test_fd (int fd) |
635 | 0 | { |
636 | 0 | if (logstream) |
637 | 0 | { |
638 | 0 | int tmp = _gpgrt_fileno (logstream); |
639 | 0 | if ( tmp != -1 && tmp == fd) |
640 | 0 | return 1; |
641 | 0 | } |
642 | 0 | if (log_socket != -1 && log_socket == fd) |
643 | 0 | return 1; |
644 | 0 | return 0; |
645 | 0 | } |
646 | | |
647 | | int |
648 | | _gpgrt_log_get_fd (void) |
649 | 0 | { |
650 | 0 | return logstream? _gpgrt_fileno (logstream) : -1; |
651 | 0 | } |
652 | | |
653 | | estream_t |
654 | | _gpgrt_log_get_stream (void) |
655 | 0 | { |
656 | 0 | if (!logstream) |
657 | 0 | { |
658 | | /* Make sure a log stream has been set. */ |
659 | 0 | _gpgrt_log_set_sink (NULL, NULL, -1); |
660 | 0 | if (!logstream) |
661 | 0 | { |
662 | 0 | fputs ("gpgrt fatal: failed to init log stream\n", stderr); |
663 | 0 | _gpgrt_abort (); |
664 | 0 | } |
665 | 0 | } |
666 | 0 | return logstream; |
667 | 0 | } |
668 | | |
669 | | |
670 | | /* Add a function F to the list of functions called after a log_fatal |
671 | | * or log_bug right before terminating the process. If a function |
672 | | * with that address has already been registered, it is not added a |
673 | | * second time. */ |
674 | | void |
675 | | _gpgrt_add_post_log_func (void (*f)(int)) |
676 | 10 | { |
677 | 10 | post_log_func_item_t item; |
678 | | |
679 | 10 | for (item = post_log_func_list; item; item = item->next) |
680 | 0 | if (item->func == f) |
681 | 0 | return; /* Function has already been registered. */ |
682 | | |
683 | | /* We use a standard malloc here. */ |
684 | 10 | item = malloc (sizeof *item); |
685 | 10 | if (item) |
686 | 10 | { |
687 | 10 | item->func = f; |
688 | 10 | item->next = post_log_func_list; |
689 | 10 | post_log_func_list = item; |
690 | 10 | } |
691 | 0 | else |
692 | 0 | _gpgrt_log_fatal ("out of core in gpgrt_add_post_log_func\n"); |
693 | 10 | } |
694 | | |
695 | | |
696 | | /* Run the post log function handlers. These are only called for |
697 | | * fatal and bug errors and should be aware that the process will |
698 | | * terminate. */ |
699 | | static void |
700 | | run_post_log_funcs (int level) |
701 | 0 | { |
702 | 0 | static int running; /* Just to avoid recursive calls. */ |
703 | 0 | post_log_func_item_t next; |
704 | 0 | void (*f)(int); |
705 | |
|
706 | 0 | if (running) |
707 | 0 | return; |
708 | 0 | running = 1; |
709 | |
|
710 | 0 | while (post_log_func_list) |
711 | 0 | { |
712 | 0 | next = post_log_func_list->next; |
713 | 0 | f = post_log_func_list->func; |
714 | 0 | post_log_func_list->func = NULL; |
715 | 0 | post_log_func_list = next; |
716 | 0 | if (f) |
717 | 0 | f (level); |
718 | 0 | } |
719 | 0 | } |
720 | | |
721 | | |
722 | | |
723 | | /* A filter used with the fprintf_sf function to sanitize the args for |
724 | | * "%s" format specifiers. */ |
725 | | static char * |
726 | | fmt_string_filter (const char *string, int no, void *opaque) |
727 | 0 | { |
728 | 0 | struct fmt_string_filter_s *state = opaque; |
729 | 0 | const unsigned char *p; |
730 | 0 | size_t buflen; |
731 | 0 | char *d; |
732 | 0 | int any; |
733 | |
|
734 | 0 | if (no == -1) |
735 | 0 | { |
736 | | /* The printf engine asked us to release resources. */ |
737 | 0 | if (state->last_result) |
738 | 0 | { |
739 | 0 | _gpgrt_free (state->last_result); |
740 | 0 | state->last_result = NULL; |
741 | 0 | } |
742 | 0 | return NULL; |
743 | 0 | } |
744 | | |
745 | 0 | if (!string) |
746 | 0 | return NULL; /* Nothing to filter - printf handles NULL nicely. */ |
747 | | |
748 | | /* Check whether escaping is needed and count needed length. */ |
749 | 0 | any = 0; |
750 | 0 | buflen = 1; |
751 | 0 | for (p = (const unsigned char *)string; *p; p++) |
752 | 0 | { |
753 | 0 | switch (*p) |
754 | 0 | { |
755 | 0 | case '\n': |
756 | 0 | case '\r': |
757 | 0 | case '\f': |
758 | 0 | case '\v': |
759 | 0 | case '\b': |
760 | 0 | case '\t': |
761 | 0 | case '\a': |
762 | 0 | case '\\': |
763 | 0 | buflen += 2; |
764 | 0 | any = 1; |
765 | 0 | break; |
766 | 0 | default: |
767 | 0 | if (*p < 0x20 || *p == 0x7f) |
768 | 0 | { |
769 | 0 | buflen += 5; |
770 | 0 | any = 1; |
771 | 0 | } |
772 | 0 | else |
773 | 0 | buflen++; |
774 | 0 | } |
775 | 0 | } |
776 | 0 | if (!any) |
777 | 0 | return (char*)string; /* Nothing to escape. */ |
778 | | |
779 | | /* Create a buffer and escape the input. */ |
780 | 0 | _gpgrt_free (state->last_result); |
781 | 0 | state->last_result = _gpgrt_malloc (buflen); |
782 | 0 | if (!state->last_result) |
783 | 0 | return "[out_of_core_in_format_string_filter]"; |
784 | | |
785 | 0 | d = state->last_result; |
786 | 0 | for (p = (const unsigned char *)string; *p; p++) |
787 | 0 | { |
788 | 0 | switch (*p) |
789 | 0 | { |
790 | 0 | case '\n': *d++ = '\\'; *d++ = 'n'; break; |
791 | 0 | case '\r': *d++ = '\\'; *d++ = 'r'; break; |
792 | 0 | case '\f': *d++ = '\\'; *d++ = 'f'; break; |
793 | 0 | case '\v': *d++ = '\\'; *d++ = 'v'; break; |
794 | 0 | case '\b': *d++ = '\\'; *d++ = 'b'; break; |
795 | 0 | case '\t': *d++ = '\\'; *d++ = 't'; break; |
796 | 0 | case '\a': *d++ = '\\'; *d++ = 'a'; break; |
797 | 0 | case '\\': *d++ = '\\'; *d++ = '\\'; break; |
798 | | |
799 | 0 | default: |
800 | 0 | if (*p < 0x20 || *p == 0x7f) |
801 | 0 | { |
802 | 0 | snprintf (d, 5, "\\x%02x", *p); |
803 | 0 | d += 4; |
804 | 0 | } |
805 | 0 | else |
806 | 0 | *d++ = *p; |
807 | 0 | } |
808 | 0 | } |
809 | 0 | *d = 0; |
810 | 0 | return state->last_result; |
811 | 0 | } |
812 | | |
813 | | |
814 | | /* Note: LOGSTREAM is expected to be locked. */ |
815 | | static int |
816 | | print_prefix (int level, int leading_backspace) |
817 | 0 | { |
818 | 0 | int rc; |
819 | 0 | int length = 0; |
820 | |
|
821 | 0 | if (level != GPGRT_LOGLVL_CONT) |
822 | 0 | { /* Note this does not work for multiple line logging as we would |
823 | | * need to print to a buffer first */ |
824 | 0 | if (with_time && !force_prefixes) |
825 | 0 | { |
826 | 0 | struct tm *tp; |
827 | 0 | time_t atime = time (NULL); |
828 | |
|
829 | 0 | tp = localtime (&atime); |
830 | 0 | rc = _gpgrt_fprintf_unlocked (logstream, |
831 | 0 | "%04d-%02d-%02d %02d:%02d:%02d ", |
832 | 0 | 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday, |
833 | 0 | tp->tm_hour, tp->tm_min, tp->tm_sec ); |
834 | 0 | if (rc > 0) |
835 | 0 | length += rc; |
836 | 0 | } |
837 | 0 | if (with_prefix || force_prefixes) |
838 | 0 | { |
839 | 0 | _gpgrt_fputs_unlocked (prefix_buffer, logstream); |
840 | 0 | length += strlen (prefix_buffer); |
841 | 0 | } |
842 | 0 | if (with_pid || force_prefixes) |
843 | 0 | { |
844 | 0 | unsigned long pidsuf; |
845 | 0 | int pidfmt; |
846 | |
|
847 | 0 | if (get_pid_suffix_cb && (pidfmt=get_pid_suffix_cb (&pidsuf))) |
848 | 0 | rc = _gpgrt_fprintf_unlocked (logstream, |
849 | 0 | pidfmt == 1? "[%u.%lu]":"[%u.%lx]", |
850 | 0 | (unsigned int)getpid (), pidsuf); |
851 | 0 | else |
852 | 0 | rc = _gpgrt_fprintf_unlocked (logstream, "[%u]", |
853 | 0 | (unsigned int)getpid ()); |
854 | 0 | if (rc > 0) |
855 | 0 | length += rc; |
856 | 0 | } |
857 | 0 | if ((!with_time && (with_prefix || with_pid)) || force_prefixes) |
858 | 0 | { |
859 | 0 | _gpgrt_putc_unlocked (':', logstream); |
860 | 0 | length++; |
861 | 0 | } |
862 | | /* A leading backspace suppresses the extra space so that we can |
863 | | correctly output, programname, filename and linenumber. */ |
864 | 0 | if (!leading_backspace |
865 | 0 | && (with_time || with_prefix || with_pid || force_prefixes)) |
866 | 0 | { |
867 | 0 | _gpgrt_putc_unlocked (' ', logstream); |
868 | 0 | length++; |
869 | 0 | } |
870 | 0 | } |
871 | |
|
872 | 0 | switch (level) |
873 | 0 | { |
874 | 0 | case GPGRT_LOGLVL_BEGIN: break; |
875 | 0 | case GPGRT_LOGLVL_CONT: break; |
876 | 0 | case GPGRT_LOGLVL_INFO: break; |
877 | 0 | case GPGRT_LOGLVL_WARN: break; |
878 | 0 | case GPGRT_LOGLVL_ERROR: break; |
879 | 0 | case GPGRT_LOGLVL_FATAL: |
880 | 0 | _gpgrt_fputs_unlocked ("Fatal: ", logstream); |
881 | 0 | length += 7; |
882 | 0 | break; |
883 | 0 | case GPGRT_LOGLVL_BUG: |
884 | 0 | _gpgrt_fputs_unlocked ("Ohhhh jeeee: ", logstream); |
885 | 0 | length += 13; |
886 | 0 | break; |
887 | 0 | case GPGRT_LOGLVL_DEBUG: |
888 | 0 | _gpgrt_fputs_unlocked ("DBG: ", logstream); |
889 | 0 | length += 5; |
890 | 0 | break; |
891 | 0 | default: |
892 | 0 | rc = _gpgrt_fprintf_unlocked (logstream, |
893 | 0 | "[Unknown log level %d]: ", level); |
894 | 0 | if (rc > 0) |
895 | 0 | length += rc; |
896 | 0 | break; |
897 | 0 | } |
898 | | |
899 | 0 | return length; |
900 | 0 | } |
901 | | |
902 | | |
903 | | /* Internal worker function. Exported so that we can use it in |
904 | | * visibility.c. Returns the number of characters printed sans prefix |
905 | | * or 0 if the line ends in a LF. */ |
906 | | int |
907 | | _gpgrt_logv_internal (int level, int ignore_arg_ptr, const char *extrastring, |
908 | | const char *prefmt, const char *fmt, va_list arg_ptr) |
909 | 0 | { |
910 | 0 | int leading_backspace = (fmt && *fmt == '\b'); |
911 | 0 | int length, prefixlen; |
912 | 0 | int rc; |
913 | |
|
914 | 0 | if (!logstream) |
915 | 0 | { |
916 | | #ifdef HAVE_W32_SYSTEM |
917 | | char *tmp; |
918 | | |
919 | | tmp = (no_registry |
920 | | ? NULL |
921 | | : _gpgrt_w32_reg_query_string (NULL, "Software\\\\GNU\\\\GnuPG", |
922 | | "DefaultLogFile")); |
923 | | _gpgrt_log_set_sink (tmp && *tmp? tmp : NULL, NULL, -1); |
924 | | _gpgrt_free (tmp); |
925 | | #else |
926 | | /* Make sure a log stream has been set. */ |
927 | 0 | _gpgrt_log_set_sink (NULL, NULL, -1); |
928 | 0 | #endif |
929 | 0 | if (!logstream) |
930 | 0 | { |
931 | 0 | fputs ("gpgrt fatal: failed to init log stream\n", stderr); |
932 | 0 | _gpgrt_abort (); |
933 | 0 | } |
934 | 0 | } |
935 | | |
936 | 0 | _gpgrt_flockfile (logstream); |
937 | 0 | if (missing_lf && level != GPGRT_LOGLVL_CONT) |
938 | 0 | _gpgrt_putc_unlocked ('\n', logstream ); |
939 | 0 | missing_lf = 0; |
940 | |
|
941 | 0 | length = print_prefix (level, leading_backspace); |
942 | 0 | if (leading_backspace) |
943 | 0 | fmt++; |
944 | |
|
945 | 0 | if (fmt) |
946 | 0 | { |
947 | 0 | if (prefmt) |
948 | 0 | { |
949 | 0 | _gpgrt_fputs_unlocked (prefmt, logstream); |
950 | 0 | length += strlen (prefmt); |
951 | 0 | } |
952 | 0 | prefixlen = length; |
953 | |
|
954 | 0 | if (ignore_arg_ptr) |
955 | 0 | { /* This is used by log_string and comes with the extra |
956 | | * feature that after a LF the next line is indented by the |
957 | | * length of the prefix. Note that we do not yet include |
958 | | * the length of the timestamp and pid in the indent |
959 | | * computation. */ |
960 | 0 | const char *p, *pend; |
961 | |
|
962 | 0 | for (p = fmt; (pend = strchr (p, '\n')); p = pend+1) |
963 | 0 | { |
964 | 0 | rc = _gpgrt_fprintf_unlocked (logstream, "%*s%.*s", |
965 | 0 | (int)((p != fmt |
966 | 0 | && (with_prefix || force_prefixes)) |
967 | 0 | ?strlen (prefix_buffer)+2:0), "", |
968 | 0 | (int)(pend - p)+1, p); |
969 | 0 | if (rc > 0) |
970 | 0 | length += rc; |
971 | 0 | } |
972 | 0 | _gpgrt_fputs_unlocked (p, logstream); |
973 | 0 | length += strlen (p); |
974 | 0 | } |
975 | 0 | else |
976 | 0 | { |
977 | 0 | struct fmt_string_filter_s sf = {NULL}; |
978 | |
|
979 | 0 | rc = _gpgrt_vfprintf_unlocked (logstream, fmt_string_filter, &sf, |
980 | 0 | fmt, arg_ptr); |
981 | 0 | if (rc > 0) |
982 | 0 | length += rc; |
983 | 0 | } |
984 | |
|
985 | 0 | if (*fmt && fmt[strlen(fmt)-1] != '\n') |
986 | 0 | missing_lf = 1; |
987 | 0 | } |
988 | 0 | else |
989 | 0 | prefixlen = length; |
990 | | |
991 | | /* If we have an EXTRASTRING print it now while we still hold the |
992 | | * lock on the logstream. */ |
993 | 0 | if (extrastring) |
994 | 0 | { |
995 | 0 | int c; |
996 | |
|
997 | 0 | if (missing_lf) |
998 | 0 | { |
999 | 0 | _gpgrt_putc_unlocked ('\n', logstream); |
1000 | 0 | missing_lf = 0; |
1001 | 0 | length = 0; |
1002 | 0 | } |
1003 | 0 | length += print_prefix (level, leading_backspace); |
1004 | 0 | _gpgrt_fputs_unlocked (">> ", logstream); |
1005 | 0 | length += 3; |
1006 | 0 | missing_lf = 1; |
1007 | 0 | while ((c = *extrastring++)) |
1008 | 0 | { |
1009 | 0 | missing_lf = 1; |
1010 | 0 | if (c == '\\') |
1011 | 0 | { |
1012 | 0 | _gpgrt_fputs_unlocked ("\\\\", logstream); |
1013 | 0 | length += 2; |
1014 | 0 | } |
1015 | 0 | else if (c == '\r') |
1016 | 0 | { |
1017 | 0 | _gpgrt_fputs_unlocked ("\\r", logstream); |
1018 | 0 | length += 2; |
1019 | 0 | } |
1020 | 0 | else if (c == '\n') |
1021 | 0 | { |
1022 | 0 | _gpgrt_fputs_unlocked ("\\n\n", logstream); |
1023 | 0 | length = 0; |
1024 | 0 | if (*extrastring) |
1025 | 0 | { |
1026 | 0 | length += print_prefix (level, leading_backspace); |
1027 | 0 | _gpgrt_fputs_unlocked (">> ", logstream); |
1028 | 0 | length += 3; |
1029 | 0 | } |
1030 | 0 | else |
1031 | 0 | missing_lf = 0; |
1032 | 0 | } |
1033 | 0 | else |
1034 | 0 | { |
1035 | 0 | _gpgrt_putc_unlocked (c, logstream); |
1036 | 0 | length++; |
1037 | 0 | } |
1038 | 0 | } |
1039 | 0 | if (missing_lf) |
1040 | 0 | { |
1041 | 0 | _gpgrt_putc_unlocked ('\n', logstream); |
1042 | 0 | length = 0; |
1043 | 0 | missing_lf = 0; |
1044 | 0 | } |
1045 | 0 | } |
1046 | |
|
1047 | 0 | if (level == GPGRT_LOGLVL_FATAL) |
1048 | 0 | { |
1049 | 0 | if (missing_lf) |
1050 | 0 | _gpgrt_putc_unlocked ('\n', logstream); |
1051 | 0 | run_post_log_funcs (level); |
1052 | 0 | _gpgrt_funlockfile (logstream); |
1053 | 0 | exit (2); |
1054 | 0 | } |
1055 | 0 | else if (level == GPGRT_LOGLVL_BUG) |
1056 | 0 | { |
1057 | 0 | if (missing_lf) |
1058 | 0 | _gpgrt_putc_unlocked ('\n', logstream ); |
1059 | 0 | run_post_log_funcs (level); |
1060 | 0 | _gpgrt_funlockfile (logstream); |
1061 | | /* Using backtrace requires a configure test and to pass |
1062 | | * -rdynamic to gcc. Thus we do not enable it now. */ |
1063 | | /* { */ |
1064 | | /* void *btbuf[20]; */ |
1065 | | /* int btidx, btlen; */ |
1066 | | /* char **btstr; */ |
1067 | | |
1068 | | /* btlen = backtrace (btbuf, DIM (btbuf)); */ |
1069 | | /* btstr = backtrace_symbols (btbuf, btlen); */ |
1070 | | /* if (btstr) */ |
1071 | | /* for (btidx=0; btidx < btlen; btidx++) */ |
1072 | | /* log_debug ("[%d] %s\n", btidx, btstr[btidx]); */ |
1073 | | /* } */ |
1074 | 0 | _gpgrt_abort (); |
1075 | 0 | } |
1076 | 0 | else |
1077 | 0 | _gpgrt_funlockfile (logstream); |
1078 | | |
1079 | | /* Bumb the error counter for log_error. */ |
1080 | 0 | if (level == GPGRT_LOGLVL_ERROR) |
1081 | 0 | _gpgrt_inc_errorcount (); |
1082 | |
|
1083 | 0 | return length > prefixlen? (length - prefixlen): length; |
1084 | 0 | } |
1085 | | |
1086 | | |
1087 | | void |
1088 | | _gpgrt_log (int level, const char *fmt, ...) |
1089 | 0 | { |
1090 | 0 | va_list arg_ptr ; |
1091 | |
|
1092 | 0 | va_start (arg_ptr, fmt) ; |
1093 | 0 | _gpgrt_logv_internal (level, 0, NULL, NULL, fmt, arg_ptr); |
1094 | 0 | va_end (arg_ptr); |
1095 | 0 | } |
1096 | | |
1097 | | |
1098 | | void |
1099 | | _gpgrt_logv (int level, const char *fmt, va_list arg_ptr) |
1100 | 0 | { |
1101 | 0 | _gpgrt_logv_internal (level, 0, NULL, NULL, fmt, arg_ptr); |
1102 | 0 | } |
1103 | | |
1104 | | |
1105 | | /* Same as log_logv but PREFIX is printed immediately before FMT. |
1106 | | * Note that PREFIX is an additional string and independent of the |
1107 | | * prefix set by gpgrt_log_set_prefix. */ |
1108 | | void |
1109 | | _gpgrt_logv_prefix (int level, const char *prefix, |
1110 | | const char *fmt, va_list arg_ptr) |
1111 | 0 | { |
1112 | 0 | _gpgrt_logv_internal (level, 0, NULL, prefix, fmt, arg_ptr); |
1113 | 0 | } |
1114 | | |
1115 | | |
1116 | | static void |
1117 | | do_log_ignore_arg (int level, const char *str, ...) |
1118 | 0 | { |
1119 | 0 | va_list arg_ptr; |
1120 | 0 | va_start (arg_ptr, str); |
1121 | 0 | _gpgrt_logv_internal (level, 1, NULL, NULL, str, arg_ptr); |
1122 | 0 | va_end (arg_ptr); |
1123 | 0 | } |
1124 | | |
1125 | | |
1126 | | /* Log STRING at LEVEL but indent from the second line on by the |
1127 | | * length of the prefix. */ |
1128 | | void |
1129 | | _gpgrt_log_string (int level, const char *string) |
1130 | 0 | { |
1131 | | /* We need a dummy arg_ptr, but there is no portable way to create |
1132 | | * one. So we call the _gpgrt_logv_internal function through a |
1133 | | * variadic wrapper. */ |
1134 | 0 | do_log_ignore_arg (level, string); |
1135 | 0 | } |
1136 | | |
1137 | | |
1138 | | void |
1139 | | _gpgrt_log_info (const char *fmt, ...) |
1140 | 0 | { |
1141 | 0 | va_list arg_ptr ; |
1142 | |
|
1143 | 0 | va_start (arg_ptr, fmt); |
1144 | 0 | _gpgrt_logv_internal (GPGRT_LOGLVL_INFO, 0, NULL, NULL, fmt, arg_ptr); |
1145 | 0 | va_end (arg_ptr); |
1146 | 0 | } |
1147 | | |
1148 | | |
1149 | | void |
1150 | | _gpgrt_log_error (const char *fmt, ...) |
1151 | 0 | { |
1152 | 0 | va_list arg_ptr ; |
1153 | |
|
1154 | 0 | va_start (arg_ptr, fmt); |
1155 | 0 | _gpgrt_logv_internal (GPGRT_LOGLVL_ERROR, 0, NULL, NULL, fmt, arg_ptr); |
1156 | 0 | va_end (arg_ptr); |
1157 | 0 | } |
1158 | | |
1159 | | |
1160 | | void |
1161 | | _gpgrt_log_fatal (const char *fmt, ...) |
1162 | 0 | { |
1163 | 0 | va_list arg_ptr ; |
1164 | |
|
1165 | 0 | va_start (arg_ptr, fmt); |
1166 | 0 | _gpgrt_logv_internal (GPGRT_LOGLVL_FATAL, 0, NULL, NULL, fmt, arg_ptr); |
1167 | 0 | va_end (arg_ptr); |
1168 | 0 | _gpgrt_abort (); /* Never called; just to make the compiler happy. */ |
1169 | 0 | } |
1170 | | |
1171 | | |
1172 | | void |
1173 | | _gpgrt_log_bug (const char *fmt, ...) |
1174 | 0 | { |
1175 | 0 | va_list arg_ptr ; |
1176 | |
|
1177 | 0 | va_start (arg_ptr, fmt); |
1178 | 0 | _gpgrt_logv_internal (GPGRT_LOGLVL_BUG, 0, NULL, NULL, fmt, arg_ptr); |
1179 | 0 | va_end (arg_ptr); |
1180 | 0 | _gpgrt_abort (); /* Never called; just to make the compiler happy. */ |
1181 | 0 | } |
1182 | | |
1183 | | |
1184 | | void |
1185 | | _gpgrt_log_debug (const char *fmt, ...) |
1186 | 0 | { |
1187 | 0 | va_list arg_ptr; |
1188 | |
|
1189 | 0 | va_start (arg_ptr, fmt); |
1190 | 0 | _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, NULL, NULL, fmt, arg_ptr); |
1191 | 0 | va_end (arg_ptr); |
1192 | 0 | } |
1193 | | |
1194 | | |
1195 | | /* The same as log_debug but at the end of the output STRING is |
1196 | | * printed with LFs expanded to include the prefix and a final --end-- |
1197 | | * marker. */ |
1198 | | void |
1199 | | _gpgrt_log_debug_string (const char *string, const char *fmt, ...) |
1200 | 0 | { |
1201 | 0 | va_list arg_ptr; |
1202 | |
|
1203 | 0 | va_start (arg_ptr, fmt); |
1204 | 0 | _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, string, NULL, fmt, arg_ptr); |
1205 | 0 | va_end (arg_ptr); |
1206 | 0 | } |
1207 | | |
1208 | | |
1209 | | void |
1210 | | _gpgrt_log_printf (const char *fmt, ...) |
1211 | 0 | { |
1212 | 0 | va_list arg_ptr; |
1213 | |
|
1214 | 0 | va_start (arg_ptr, fmt); |
1215 | 0 | _gpgrt_logv_internal (fmt ? GPGRT_LOGLVL_CONT : GPGRT_LOGLVL_BEGIN, |
1216 | 0 | 0, NULL, NULL, fmt, arg_ptr); |
1217 | 0 | va_end (arg_ptr); |
1218 | 0 | } |
1219 | | |
1220 | | |
1221 | | /* Flush the log - this is useful to make sure that the trailing |
1222 | | linefeed has been printed. */ |
1223 | | void |
1224 | | _gpgrt_log_flush (void) |
1225 | 0 | { |
1226 | 0 | do_log_ignore_arg (GPGRT_LOGLVL_CONT, NULL); |
1227 | 0 | } |
1228 | | |
1229 | | |
1230 | | /* Print a hexdump of (BUFFER,LENGTH). With FMT passed as NULL print |
1231 | | * just the raw dump (in this case ARG_PTR is not used), with FMT |
1232 | | * being an empty string, print a trailing linefeed, otherwise print |
1233 | | * an entire debug line with the expanded FMT followed by a possible |
1234 | | * wrapped hexdump and a final LF. */ |
1235 | | void |
1236 | | _gpgrt_logv_printhex (const void *buffer, size_t length, |
1237 | | const char *fmt, va_list arg_ptr) |
1238 | 0 | { |
1239 | 0 | int wrap = 0; |
1240 | 0 | int wrapamount = 0; |
1241 | 0 | int cnt = 0; |
1242 | 0 | const unsigned char *p; |
1243 | 0 | int trunc = 0; /* Only print a shortened string. */ |
1244 | | |
1245 | | /* FIXME: This printing is not yet protected by _gpgrt_flockfile. */ |
1246 | 0 | if (fmt && *fmt) |
1247 | 0 | { |
1248 | 0 | const char *s; |
1249 | |
|
1250 | 0 | if (*fmt == '|' && fmt[1] == '!' && (s=strchr (fmt+2, '|')) && s[1]) |
1251 | 0 | { |
1252 | | /* Skip initial keywords and parse them. */ |
1253 | 0 | fmt += 2; |
1254 | 0 | if (strstr (fmt, "trunc")) |
1255 | 0 | trunc = 1; |
1256 | |
|
1257 | 0 | fmt = s+1; |
1258 | 0 | } |
1259 | |
|
1260 | 0 | wrapamount = _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, NULL, NULL, |
1261 | 0 | fmt, arg_ptr); |
1262 | 0 | wrap = 1; |
1263 | 0 | } |
1264 | |
|
1265 | 0 | if (length) |
1266 | 0 | { |
1267 | 0 | if (wrap) |
1268 | 0 | _gpgrt_log_printf (" "); |
1269 | |
|
1270 | 0 | for (p = buffer; length--; p++) |
1271 | 0 | { |
1272 | 0 | _gpgrt_log_printf ("%02x", *p); |
1273 | 0 | if (wrap && ++cnt == 32 && length) |
1274 | 0 | { |
1275 | 0 | if (trunc) |
1276 | 0 | { |
1277 | 0 | _gpgrt_log_printf (" …"); |
1278 | 0 | break; |
1279 | 0 | } |
1280 | | |
1281 | 0 | cnt = 0; |
1282 | | /* (we indicate continuations with a backslash) */ |
1283 | 0 | _gpgrt_log_printf (" \\\n"); |
1284 | 0 | if (wrap) |
1285 | 0 | _gpgrt_log_debug ("%*s", wrapamount, ""); |
1286 | 0 | else |
1287 | 0 | _gpgrt_log_debug ("%s", ""); |
1288 | 0 | if (fmt && *fmt) |
1289 | 0 | _gpgrt_log_printf (" "); |
1290 | 0 | } |
1291 | 0 | } |
1292 | 0 | } |
1293 | |
|
1294 | 0 | if (fmt) |
1295 | 0 | _gpgrt_log_printf ("\n"); |
1296 | 0 | } |
1297 | | |
1298 | | |
1299 | | /* Print a hexdump of (BUFFER,LENGTH). With FMT passed as NULL print |
1300 | | * just the raw dump, with FMT being an empty string, print a trailing |
1301 | | * linefeed, otherwise print an entire debug line with the expanded |
1302 | | * FMT followed by the hexdump and a final LF. */ |
1303 | | void |
1304 | | _gpgrt_log_printhex (const void *buffer, size_t length, |
1305 | | const char *fmt, ...) |
1306 | 0 | { |
1307 | 0 | va_list arg_ptr; |
1308 | |
|
1309 | 0 | if (fmt) |
1310 | 0 | { |
1311 | 0 | va_start (arg_ptr, fmt); |
1312 | 0 | _gpgrt_logv_printhex (buffer, length, fmt, arg_ptr); |
1313 | 0 | va_end (arg_ptr); |
1314 | 0 | } |
1315 | 0 | else |
1316 | 0 | { |
1317 | | /* va_list is not necessary a pointer and thus we can't use NULL |
1318 | | * because that would conflict with platforms using a straight |
1319 | | * struct for it (e.g. arm64). We use a dummy variable instead; |
1320 | | * the static is a simple way zero it out so to not get |
1321 | | * complains about uninitialized use. */ |
1322 | 0 | static va_list dummy_argptr; |
1323 | |
|
1324 | 0 | _gpgrt_logv_printhex (buffer, length, NULL, dummy_argptr); |
1325 | 0 | } |
1326 | 0 | } |
1327 | | |
1328 | | |
1329 | | /* Print a microsecond timestamp followed by FMT. */ |
1330 | | void |
1331 | | _gpgrt_logv_clock (const char *fmt, va_list arg_ptr) |
1332 | 0 | { |
1333 | | #if ENABLE_LOG_CLOCK |
1334 | | static unsigned long long initial; |
1335 | | struct timespec tv; |
1336 | | unsigned long long now; |
1337 | | char clockbuf[50]; |
1338 | | |
1339 | | if (clock_gettime (CLOCK_REALTIME, &tv)) |
1340 | | { |
1341 | | _gpgrt_log_debug ("error getting the realtime clock value\n"); |
1342 | | return; |
1343 | | } |
1344 | | now = tv.tv_sec * 1000000000ull; |
1345 | | now += tv.tv_nsec; |
1346 | | |
1347 | | if (!initial) |
1348 | | initial = now; |
1349 | | |
1350 | | snprintf (clockbuf, sizeof clockbuf, "[%6llu] ", (now - initial)/1000); |
1351 | | _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, 0, NULL, clockbuf, fmt, arg_ptr); |
1352 | | |
1353 | | #else /*!ENABLE_LOG_CLOCK*/ |
1354 | | |
1355 | | /* You may need to link with -ltr to use the above code. */ |
1356 | |
|
1357 | 0 | _gpgrt_logv_internal (GPGRT_LOGLVL_DEBUG, |
1358 | 0 | 0, NULL, "[no clock] ", fmt, arg_ptr); |
1359 | |
|
1360 | 0 | #endif /*!ENABLE_LOG_CLOCK*/ |
1361 | 0 | } |
1362 | | |
1363 | | |
1364 | | /* Print a microsecond timestamp followed by FMT. */ |
1365 | | void |
1366 | | _gpgrt_log_clock (const char *fmt, ...) |
1367 | 0 | { |
1368 | 0 | va_list arg_ptr; |
1369 | |
|
1370 | 0 | va_start (arg_ptr, fmt); |
1371 | 0 | _gpgrt_logv_clock (fmt, arg_ptr); |
1372 | 0 | va_end (arg_ptr); |
1373 | 0 | } |
1374 | | |
1375 | | |
1376 | | void |
1377 | | _gpgrt__log_assert (const char *expr, const char *file, |
1378 | | int line, const char *func) |
1379 | 0 | { |
1380 | 0 | #ifdef GPGRT_HAVE_MACRO_FUNCTION |
1381 | 0 | _gpgrt_log (GPGRT_LOGLVL_BUG, "Assertion \"%s\" in %s failed (%s:%d)\n", |
1382 | 0 | expr, func, file, line); |
1383 | | #else /*!GPGRT_HAVE_MACRO_FUNCTION*/ |
1384 | | _gpgrt_log (GPGRT_LOGLVL_BUG, "Assertion \"%s\" failed (%s:%d)\n", |
1385 | | expr, file, line); |
1386 | | #endif /*!GPGRT_HAVE_MACRO_FUNCTION*/ |
1387 | 0 | _gpgrt_abort (); /* Never called; just to make the compiler happy. */ |
1388 | 0 | } |