*
* This file is part of GnuPG.
*
- * GnuPG is free software; you can redistribute it and/or modify it
- * under the terms of either
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
*
* You should have received a copies of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
- * if not, see <http://www.gnu.org/licenses/>.
+ * if not, see <https://www.gnu.org/licenses/>.
*/
#include <unistd.h>
#include <fcntl.h>
#include <assert.h>
-
+/* #include <execinfo.h> */
#define GNUPG_COMMON_NEED_AFLOCAL 1
#include "util.h"
#include "i18n.h"
#include "common-defs.h"
#include "logging.h"
+#include "sysutils.h"
#ifdef HAVE_W32_SYSTEM
# define S_IRGRP S_IRUSR
static int no_registry;
#endif
static int (*get_pid_suffix_cb)(unsigned long *r_value);
+static const char * (*socket_dir_cb)(void);
static int running_detached;
static int force_prefixes;
#ifndef HAVE_W32_SYSTEM
struct sockaddr_un srvr_addr_un;
#endif
+ const char *name_for_err = "";
size_t addrlen;
struct sockaddr *srvr_addr = NULL;
unsigned short port = 0;
pf = PF_INET;
}
#ifndef HAVE_W32_SYSTEM
- else if (!strncmp (name, "socket://", 9) && name[9])
+ else if (!strncmp (name, "socket://", 9))
name += 9;
#endif
if (af == AF_LOCAL)
{
-#ifdef HAVE_W32_SYSTEM
addrlen = 0;
-#else
+#ifndef HAVE_W32_SYSTEM
memset (&srvr_addr, 0, sizeof srvr_addr);
srvr_addr_un.sun_family = af;
- strncpy (srvr_addr_un.sun_path,
- name, sizeof (srvr_addr_un.sun_path)-1);
- srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
- srvr_addr = (struct sockaddr *)&srvr_addr_un;
- addrlen = SUN_LEN (&srvr_addr_un);
-#endif
+ if (!*name && (name = socket_dir_cb ()) && *name)
+ {
+ if (strlen (name) + 7 < sizeof (srvr_addr_un.sun_path)-1)
+ {
+ strncpy (srvr_addr_un.sun_path,
+ name, sizeof (srvr_addr_un.sun_path)-1);
+ strcat (srvr_addr_un.sun_path, "/S.log");
+ srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
+ srvr_addr = (struct sockaddr *)&srvr_addr_un;
+ addrlen = SUN_LEN (&srvr_addr_un);
+ name_for_err = srvr_addr_un.sun_path;
+ }
+ }
+ else
+ {
+ if (*name && strlen (name) < sizeof (srvr_addr_un.sun_path)-1)
+ {
+ strncpy (srvr_addr_un.sun_path,
+ name, sizeof (srvr_addr_un.sun_path)-1);
+ srvr_addr_un.sun_path[sizeof (srvr_addr_un.sun_path)-1] = 0;
+ srvr_addr = (struct sockaddr *)&srvr_addr_un;
+ addrlen = SUN_LEN (&srvr_addr_un);
+ }
+ }
+#endif /*!HAVE_W32SYSTEM*/
}
else
{
{
if (!cookie->quiet && !running_detached
&& isatty (es_fileno (es_stderr)))
- es_fprintf (es_stderr, "can't connect to '%s': %s\n",
- cookie->name, strerror(errno));
+ es_fprintf (es_stderr, "can't connect to '%s%s': %s\n",
+ cookie->name, name_for_err, strerror(errno));
sock_close (cookie->fd);
cookie->fd = -1;
}
if (name && !strncmp (name, "tcp://", 6) && name[6])
want_socket = 1;
#ifndef HAVE_W32_SYSTEM
- else if (name && !strncmp (name, "socket://", 9) && name[9])
+ else if (name && !strncmp (name, "socket://", 9))
want_socket = 2;
#endif /*HAVE_W32_SYSTEM*/
#ifdef HAVE_W32CE_SYSTEM
void
log_set_fd (int fd)
{
+ if (! gnupg_fd_valid (fd))
+ log_fatal ("logger-fd is invalid: %s\n", strerror (errno));
+
set_file_fd (NULL, fd);
}
+/* Set a function to retrieve the directory name of a socket if
+ * only "socket://" has been given to log_set_file. */
+void
+log_set_socket_dir_cb (const char *(*fnc)(void))
+{
+ socket_dir_cb = fnc;
+}
+
+
void
log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value))
{
return logstream;
}
+
static void
-do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
+print_prefix (int level, int leading_backspace)
{
- if (!logstream)
- {
-#ifdef HAVE_W32_SYSTEM
- char *tmp;
-
- tmp = (no_registry
- ? NULL
- : read_w32_registry_string (NULL, GNUPG_REGISTRY_DIR,
- "DefaultLogFile"));
- log_set_file (tmp && *tmp? tmp : NULL);
- xfree (tmp);
-#else
- log_set_file (NULL); /* Make sure a log stream has been set. */
-#endif
- assert (logstream);
- }
-
- es_flockfile (logstream);
- if (missing_lf && level != GPGRT_LOG_CONT)
- es_putc_unlocked ('\n', logstream );
- missing_lf = 0;
-
if (level != GPGRT_LOG_CONT)
{ /* Note this does not work for multiple line logging as we would
* need to print to a buffer first */
else
es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ());
}
- if (!with_time || force_prefixes)
+ if ((!with_time && (with_prefix || with_pid)) || force_prefixes)
es_putc_unlocked (':', logstream);
/* A leading backspace suppresses the extra space so that we can
correctly output, programname, filename and linenumber. */
- if (fmt && *fmt == '\b')
- fmt++;
- else
+ if (!leading_backspace
+ && (with_time || with_prefix || with_pid || force_prefixes))
es_putc_unlocked (' ', logstream);
}
es_fprintf_unlocked (logstream,"[Unknown log level %d]: ", level);
break;
}
+}
+
+
+static void
+do_logv (int level, int ignore_arg_ptr, const char *extrastring,
+ const char *prefmt, const char *fmt, va_list arg_ptr)
+{
+ int leading_backspace = (fmt && *fmt == '\b');
+
+ if (!logstream)
+ {
+#ifdef HAVE_W32_SYSTEM
+ char *tmp;
+
+ tmp = (no_registry
+ ? NULL
+ : read_w32_registry_string (NULL, GNUPG_REGISTRY_DIR,
+ "DefaultLogFile"));
+ log_set_file (tmp && *tmp? tmp : NULL);
+ xfree (tmp);
+#else
+ log_set_file (NULL); /* Make sure a log stream has been set. */
+#endif
+ assert (logstream);
+ }
+
+ es_flockfile (logstream);
+ if (missing_lf && level != GPGRT_LOG_CONT)
+ es_putc_unlocked ('\n', logstream );
+ missing_lf = 0;
+
+ print_prefix (level, leading_backspace);
+ if (leading_backspace)
+ fmt++;
if (fmt)
{
+ if (prefmt)
+ es_fputs_unlocked (prefmt, logstream);
+
if (ignore_arg_ptr)
{ /* This is used by log_string and comes with the extra
* feature that after a LF the next line is indent at the
missing_lf = 1;
}
+ /* If we have an EXTRASTRING print it now while we still hold the
+ * lock on the logstream. */
+ if (extrastring)
+ {
+ int c;
+
+ if (missing_lf)
+ {
+ es_putc_unlocked ('\n', logstream);
+ missing_lf = 0;
+ }
+ print_prefix (level, leading_backspace);
+ es_fputs_unlocked (">> ", logstream);
+ missing_lf = 1;
+ while ((c = *extrastring++))
+ {
+ missing_lf = 1;
+ if (c == '\\')
+ es_fputs_unlocked ("\\\\", logstream);
+ else if (c == '\r')
+ es_fputs_unlocked ("\\r", logstream);
+ else if (c == '\n')
+ {
+ es_fputs_unlocked ("\\n\n", logstream);
+ if (*extrastring)
+ {
+ print_prefix (level, leading_backspace);
+ es_fputs_unlocked (">> ", logstream);
+ }
+ else
+ missing_lf = 0;
+ }
+ else
+ es_putc_unlocked (c, logstream);
+ }
+ if (missing_lf)
+ {
+ es_putc_unlocked ('\n', logstream);
+ missing_lf = 0;
+ }
+ }
+
if (level == GPGRT_LOG_FATAL)
{
if (missing_lf)
if (missing_lf)
es_putc_unlocked ('\n', logstream );
es_funlockfile (logstream);
+ /* Using backtrace requires a configure test and to pass
+ * -rdynamic to gcc. Thus we do not enable it now. */
+ /* { */
+ /* void *btbuf[20]; */
+ /* int btidx, btlen; */
+ /* char **btstr; */
+
+ /* btlen = backtrace (btbuf, DIM (btbuf)); */
+ /* btstr = backtrace_symbols (btbuf, btlen); */
+ /* if (btstr) */
+ /* for (btidx=0; btidx < btlen; btidx++) */
+ /* log_debug ("[%d] %s\n", btidx, btstr[btidx]); */
+ /* } */
abort ();
}
else
va_list arg_ptr ;
va_start (arg_ptr, fmt) ;
- do_logv (level, 0, fmt, arg_ptr);
+ do_logv (level, 0, NULL, NULL, fmt, arg_ptr);
va_end (arg_ptr);
}
void
log_logv (int level, const char *fmt, va_list arg_ptr)
{
- do_logv (level, 0, fmt, arg_ptr);
+ do_logv (level, 0, NULL, NULL, fmt, arg_ptr);
+}
+
+
+/* Same as log_logv but PREFIX is printed immediately before FMT.
+ * Note that PREFIX is an additional string and independent of the
+ * prefix set by log_set_prefix. */
+void
+log_logv_with_prefix (int level, const char *prefix,
+ const char *fmt, va_list arg_ptr)
+{
+ do_logv (level, 0, NULL, prefix, fmt, arg_ptr);
}
{
va_list arg_ptr;
va_start (arg_ptr, str);
- do_logv (level, 1, str, arg_ptr);
+ do_logv (level, 1, NULL, NULL, str, arg_ptr);
va_end (arg_ptr);
}
va_list arg_ptr ;
va_start (arg_ptr, fmt);
- do_logv (GPGRT_LOG_INFO, 0, fmt, arg_ptr);
+ do_logv (GPGRT_LOG_INFO, 0, NULL, NULL, fmt, arg_ptr);
va_end (arg_ptr);
}
va_list arg_ptr ;
va_start (arg_ptr, fmt);
- do_logv (GPGRT_LOG_ERROR, 0, fmt, arg_ptr);
+ do_logv (GPGRT_LOG_ERROR, 0, NULL, NULL, fmt, arg_ptr);
va_end (arg_ptr);
/* Protect against counter overflow. */
if (errorcount < 30000)
va_list arg_ptr ;
va_start (arg_ptr, fmt);
- do_logv (GPGRT_LOG_FATAL, 0, fmt, arg_ptr);
+ do_logv (GPGRT_LOG_FATAL, 0, NULL, NULL, fmt, arg_ptr);
va_end (arg_ptr);
abort (); /* Never called; just to make the compiler happy. */
}
va_list arg_ptr ;
va_start (arg_ptr, fmt);
- do_logv (GPGRT_LOG_BUG, 0, fmt, arg_ptr);
+ do_logv (GPGRT_LOG_BUG, 0, NULL, NULL, fmt, arg_ptr);
va_end (arg_ptr);
abort (); /* Never called; just to make the compiler happy. */
}
va_list arg_ptr ;
va_start (arg_ptr, fmt);
- do_logv (GPGRT_LOG_DEBUG, 0, fmt, arg_ptr);
+ do_logv (GPGRT_LOG_DEBUG, 0, NULL, NULL, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+
+/* The same as log_debug but at the end of the output STRING is
+ * printed with LFs expanded to include the prefix and a final --end--
+ * marker. */
+void
+log_debug_with_string (const char *string, const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ do_logv (GPGRT_LOG_DEBUG, 0, string, NULL, fmt, arg_ptr);
va_end (arg_ptr);
}
va_list arg_ptr;
va_start (arg_ptr, fmt);
- do_logv (fmt ? GPGRT_LOG_CONT : GPGRT_LOG_BEGIN, 0, fmt, arg_ptr);
+ do_logv (fmt ? GPGRT_LOG_CONT : GPGRT_LOG_BEGIN, 0, NULL, NULL, fmt, arg_ptr);
va_end (arg_ptr);
}
_log_assert (const char *expr, const char *file, int line)
{
log_log (GPGRT_LOG_BUG, "Assertion \"%s\" failed (%s:%d)\n",
- file, line, func);
+ expr, file, line);
abort (); /* Never called; just to make the compiler happy. */
}
#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/