Coverage Report

Created: 2024-11-21 07:03

/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
}