Imported Upstream version 2.1.19
[platform/upstream/gpg2.git] / common / logging.c
index 9175b4f..18c40b3 100644 (file)
@@ -4,8 +4,8 @@
  *
  * 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
@@ -26,7 +26,7 @@
  *
  * 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
@@ -104,6 +105,7 @@ static int with_pid;
 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;
 
@@ -219,6 +221,7 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
 #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;
@@ -237,23 +240,41 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
           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
         {
@@ -352,8 +373,8 @@ fun_writer (void *cookie_arg, const void *buffer, size_t size)
             {
               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;
             }
@@ -462,7 +483,7 @@ set_file_fd (const char *name, int fd)
   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
@@ -550,10 +571,22 @@ log_set_file (const char *name)
 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))
 {
@@ -636,31 +669,10 @@ log_get_stream ()
   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 */
@@ -687,13 +699,12 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
           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);
     }
 
@@ -711,9 +722,46 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
       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
@@ -736,6 +784,48 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
         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)
@@ -748,6 +838,19 @@ do_logv (int level, int ignore_arg_ptr, const char *fmt, va_list arg_ptr)
       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
@@ -761,7 +864,7 @@ log_log (int level, const char *fmt, ...)
   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);
 }
 
@@ -769,7 +872,18 @@ log_log (int level, const char *fmt, ...)
 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);
 }
 
 
@@ -778,7 +892,7 @@ do_log_ignore_arg (int level, const char *str, ...)
 {
   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);
 }
 
@@ -800,7 +914,7 @@ log_info (const char *fmt, ...)
   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);
 }
 
@@ -811,7 +925,7 @@ log_error (const char *fmt, ...)
   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)
@@ -825,7 +939,7 @@ log_fatal (const char *fmt, ...)
   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.  */
 }
@@ -837,7 +951,7 @@ log_bug (const char *fmt, ...)
   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.  */
 }
@@ -849,7 +963,21 @@ log_debug (const char *fmt, ...)
   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);
 }
 
@@ -860,7 +988,7 @@ log_printf (const char *fmt, ...)
   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);
 }
 
@@ -964,7 +1092,7 @@ void
 _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*/