dirmngr: Implement hkps lookups using literal addresses.
[gnupg.git] / common / logging.c
index 7c54d72..0db1860 100644 (file)
@@ -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/>.
  */
 
 
@@ -54,7 +54,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <assert.h>
-
+/* #include <execinfo.h> */
 
 #define GNUPG_COMMON_NEED_AFLOCAL 1
 #include "util.h"
@@ -104,6 +104,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 +220,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 +239,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 +372,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 +482,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
@@ -554,6 +574,15 @@ log_set_fd (int 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 +665,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 +695,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,17 +718,107 @@ 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 *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 (ignore_arg_ptr)
-        es_fputs_unlocked (fmt, logstream);
+        { /* This is used by log_string and comes with the extra
+           * feature that after a LF the next line is indent at the
+           * length of the prefix.  Note that we do not yet include
+           * the length of the timestamp and pid in the indent
+           * computation.  */
+          const char *p, *pend;
+
+          for (p = fmt; (pend = strchr (p, '\n')); p = pend+1)
+            es_fprintf_unlocked (logstream, "%*s%.*s",
+                                 (int)((p != fmt
+                                        && (with_prefix || force_prefixes))
+                                       ?strlen (prefix_buffer)+2:0), "",
+                                 (int)(pend - p)+1, p);
+          es_fputs_unlocked (p, logstream);
+        }
       else
         es_vfprintf_unlocked (logstream, fmt, arg_ptr);
       if (*fmt && fmt[strlen(fmt)-1] != '\n')
         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)
@@ -734,6 +831,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
@@ -747,7 +857,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, fmt, arg_ptr);
   va_end (arg_ptr);
 }
 
@@ -755,7 +865,7 @@ 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, fmt, arg_ptr);
 }
 
 
@@ -764,17 +874,18 @@ 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, str, arg_ptr);
   va_end (arg_ptr);
 }
 
 
+/* Log STRING at LEVEL but indent from the second line on by the
+ * length of the prefix.  */
 void
 log_string (int level, const char *string)
 {
   /* We need a dummy arg_ptr, but there is no portable way to create
-     one.  So we call the do_logv function through a variadic wrapper.
-     MB: Why not just use "%s"?  */
+   * one.  So we call the do_logv function through a variadic wrapper. */
   do_log_ignore_arg (level, string);
 }
 
@@ -785,7 +896,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, fmt, arg_ptr);
   va_end (arg_ptr);
 }
 
@@ -796,7 +907,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, fmt, arg_ptr);
   va_end (arg_ptr);
   /* Protect against counter overflow.  */
   if (errorcount < 30000)
@@ -810,7 +921,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, fmt, arg_ptr);
   va_end (arg_ptr);
   abort (); /* Never called; just to make the compiler happy.  */
 }
@@ -822,7 +933,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, fmt, arg_ptr);
   va_end (arg_ptr);
   abort (); /* Never called; just to make the compiler happy.  */
 }
@@ -834,7 +945,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, 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, fmt, arg_ptr);
   va_end (arg_ptr);
 }
 
@@ -845,7 +970,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, fmt, arg_ptr);
   va_end (arg_ptr);
 }
 
@@ -949,7 +1074,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*/