Change logging to use estream. The makes logging to a socket also
authorWerner Koch <wk@gnupg.org>
Wed, 10 Mar 2010 17:22:23 +0000 (17:22 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 10 Mar 2010 17:22:23 +0000 (17:22 +0000)
work on Solaris etc.  Further changes required..  This is just a first
step.

common/ChangeLog
common/estream.c
common/estream.h
common/logging.c
common/logging.h

index 6f4b70b..5fd8b03 100644 (file)
@@ -1,5 +1,27 @@
 2010-03-10  Werner Koch  <wk@g10code.com>
 
+       * estream.c (es_func_fp_read, es_func_fp_write, es_func_fp_seek)
+       (es_func_fp_destroy): Allow a NULL FP to implement a dummy stream.
+       (do_fpopen): Ditto.
+       (es_vfprintf_unlocked): New.
+       (es_fprintf_unlocked): Make public.
+       (es_fputs_unlocked): New.
+
+       * logging.h: Replace FILE* by estream_t.
+       * logging.c: Remove USE_FUNWRITER cpp conditional because we now
+       use estream.
+       (my_funopen_hook_ret_t, my_funopen_hook_size_t): Replace by
+       ssize_t.
+       (log_get_stream): Change to return an estream_t.
+       (set_file_fd): Always close the log stream because it can't be
+       assigned to stderr or stdout directly.  Use a dummy estream as
+       last resort log stream.
+       (log_test_fd, log_get_fd): Use es_fileno.
+       (log_get_stream): Assert that we have a log stream.
+       (do_logv): Use estream functions and lock the output.
+
+2010-03-10  Werner Koch  <wk@g10code.com>
+
        * util.h: Replace jnlib path part by common.
        (snprintf): Use the replacement macro on all platforms.
 
index af7da70..dfa2de4 100644 (file)
@@ -869,7 +869,10 @@ es_func_fp_read (void *cookie, void *buffer, size_t size)
   estream_cookie_fp_t file_cookie = cookie;
   ssize_t bytes_read;
 
-  bytes_read = fread (buffer, 1, size, file_cookie->fp);
+  if (file_cookie->fp)
+    bytes_read = fread (buffer, 1, size, file_cookie->fp);
+  else
+    bytes_read = 0;
   if (!bytes_read && ferror (file_cookie->fp))
     return -1;
   return bytes_read;
@@ -883,7 +886,11 @@ es_func_fp_write (void *cookie, const void *buffer, size_t size)
   estream_cookie_fp_t file_cookie = cookie;
   size_t bytes_written;
 
-  bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
+
+  if (file_cookie->fp)
+    bytes_written = fwrite (buffer, 1, size, file_cookie->fp);
+  else
+    bytes_written = size; /* Successfully written to the bit bucket.  */
   if (bytes_written != size)
     return -1;
   return bytes_written;
@@ -896,17 +903,25 @@ es_func_fp_seek (void *cookie, off_t *offset, int whence)
   estream_cookie_fp_t file_cookie = cookie;
   long int offset_new;
 
+  if (!file_cookie->fp)
+    {
+      _set_errno (ESPIPE);
+      return -1; 
+    }
+
   if ( fseek (file_cookie->fp, (long int)*offset, whence) )
     {
-      fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", errno,strerror (errno));
-    return -1;
+      /* fprintf (stderr, "\nfseek failed: errno=%d (%s)\n", */
+      /*          errno,strerror (errno)); */
+      return -1;
     }
 
   offset_new = ftell (file_cookie->fp);
   if (offset_new == -1)
     {
-      fprintf (stderr, "\nftell failed: errno=%d (%s)\n", errno,strerror (errno));
-    return -1;
+      /* fprintf (stderr, "\nftell failed: errno=%d (%s)\n",  */
+      /*          errno,strerror (errno)); */
+      return -1;
     }
   *offset = offset_new;
   return 0;
@@ -921,8 +936,13 @@ es_func_fp_destroy (void *cookie)
 
   if (fp_cookie)
     {
-      fflush (fp_cookie->fp);
-      err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
+      if (fp_cookie->fp)
+        {
+          fflush (fp_cookie->fp);
+          err = fp_cookie->no_close? 0 : fclose (fp_cookie->fp);
+        }
+      else
+        err = 0;
       mem_free (fp_cookie);
     }
   else
@@ -2268,13 +2288,14 @@ do_fpopen (FILE *fp, const char *mode, int no_close)
   if (err)
     goto out;
 
-  fflush (fp);
+  if (fp)
+    fflush (fp);
   err = es_func_fp_create (&cookie, fp, modeflags, no_close);
   if (err)
     goto out;
-
+  
   create_called = 1;
-  err = es_create (&stream, cookie, fileno (fp), estream_functions_fp,
+  err = es_create (&stream, cookie, fp? fileno (fp):-1, estream_functions_fp,
                    modeflags);
 
  out:
@@ -2738,6 +2759,17 @@ es_fgets (char *ES__RESTRICT buffer, int length, estream_t ES__RESTRICT stream)
 
 
 int
+es_fputs_unlocked (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
+{
+  size_t length;
+  int err;
+
+  length = strlen (s);
+  err = es_writen (stream, s, length, NULL);
+  return err ? EOF : 0;
+}
+
+int
 es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream)
 {
   size_t length;
@@ -2932,6 +2964,15 @@ es_free (void *a)
 
 
 int
+es_vfprintf_unlocked (estream_t ES__RESTRICT stream,
+                      const char *ES__RESTRICT format,
+                      va_list ap)
+{
+  return es_print (stream, format, ap);
+}
+
+
+int
 es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
             va_list ap)
 {
@@ -2945,9 +2986,9 @@ es_vfprintf (estream_t ES__RESTRICT stream, const char *ES__RESTRICT format,
 }
 
 
-static int
+int
 es_fprintf_unlocked (estream_t ES__RESTRICT stream,
-           const char *ES__RESTRICT format, ...)
+                     const char *ES__RESTRICT format, ...)
 {
   int ret;
   
index b22c5de..477afac 100644 (file)
 #define es_fwrite             _ESTREAM_PREFIX(es_fwrite)
 #define es_fgets              _ESTREAM_PREFIX(es_fgets)
 #define es_fputs              _ESTREAM_PREFIX(es_fputs)
+#define es_fputs_unlocked     _ESTREAM_PREFIX(es_fputs_unlocked)
 #define es_getline            _ESTREAM_PREFIX(es_getline)
 #define es_read_line          _ESTREAM_PREFIX(es_read_line)
 #define es_free               _ESTREAM_PREFIX(es_free)
-#define es_fprf               _ESTREAM_PREFIX(es_fprf)
-#define es_vfprf              _ESTREAM_PREFIX(es_vfprf)
+#define es_fprintf            _ESTREAM_PREFIX(es_fprintf)
+#define es_fprintf_unlocked   _ESTREAM_PREFIX(es_fprintf_unlocked)
+#define es_vfprintf           _ESTREAM_PREFIX(es_vfprint)
+#define es_vfprintf_unlocked  _ESTREAM_PREFIX(es_vfprint_unlocked)
 #define es_setvbuf            _ESTREAM_PREFIX(es_setvbuf)
 #define es_setbuf             _ESTREAM_PREFIX(es_setbuf)
 #define es_tmpfile            _ESTREAM_PREFIX(es_tmpfile)
@@ -311,6 +314,8 @@ size_t es_fwrite (const void *ES__RESTRICT ptr, size_t size, size_t memb,
 
 char *es_fgets (char *ES__RESTRICT s, int n, estream_t ES__RESTRICT stream);
 int es_fputs (const char *ES__RESTRICT s, estream_t ES__RESTRICT stream);
+int es_fputs_unlocked (const char *ES__RESTRICT s,
+                       estream_t ES__RESTRICT stream);
 
 ssize_t es_getline (char *ES__RESTRICT *ES__RESTRICT lineptr,
                    size_t *ES__RESTRICT n,
@@ -323,9 +328,17 @@ void es_free (void *a);
 int es_fprintf (estream_t ES__RESTRICT stream,
                const char *ES__RESTRICT format, ...)
      _ESTREAM_GCC_A_PRINTF(2,3);
+int es_fprintf_unlocked (estream_t ES__RESTRICT stream,
+                         const char *ES__RESTRICT format, ...)
+     _ESTREAM_GCC_A_PRINTF(2,3);
+
 int es_vfprintf (estream_t ES__RESTRICT stream,
                 const char *ES__RESTRICT format, va_list ap)
      _ESTREAM_GCC_A_PRINTF(2,0);
+int es_vfprintf_unlocked (estream_t ES__RESTRICT stream,
+                          const char *ES__RESTRICT format, va_list ap)
+     _ESTREAM_GCC_A_PRINTF(2,0);
+
 int es_setvbuf (estream_t ES__RESTRICT stream,
                char *ES__RESTRICT buf, int mode, size_t size);
 void es_setbuf (estream_t ES__RESTRICT stream, char *ES__RESTRICT buf);
index 028697b..c0e01da 100644 (file)
@@ -1,6 +1,6 @@
 /* logging.c - Useful logging functions
- * Copyright (C) 1998, 1999, 2000, 2001, 2003,
- *               2004, 2005, 2006, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 
+ *               2009, 2010 Free Software Foundation, Inc.
  *
  * This file is part of JNLIB.
  *
 #include "libjnlib-config.h"
 #include "logging.h"
 
-#if defined (HAVE_FOPENCOOKIE) ||  defined (HAVE_FUNOPEN)
-#define USE_FUNWRITER 1
-#endif
-
-#ifdef HAVE_FOPENCOOKIE
-typedef ssize_t my_funopen_hook_ret_t;
-typedef size_t  my_funopen_hook_size_t;
-#else
-typedef int     my_funopen_hook_ret_t;
-typedef int     my_funopen_hook_size_t;
-#endif
 
-
-static FILE *logstream;
+static estream_t logstream;
 static int log_socket = -1;
 static char prefix_buffer[80];
 static int with_time;
@@ -86,10 +74,10 @@ log_inc_errorcount (void)
 }
 
 
-/* The follwing 3 functions are used by funopen to write logs to a
-   socket. */
-#ifdef USE_FUNWRITER
-struct fun_cookie_s {
+/* The following 3 functions are used by es_fopencookie to write logs
+   to a socket.  */
+struct fun_cookie_s
+{
   int fd;
   int quiet;
   int want_socket;
@@ -97,6 +85,7 @@ struct fun_cookie_s {
   char name[1];
 };
 
+
 /* Write NBYTES of BUFFER to file descriptor FD. */
 static int
 writen (int fd, const void *buffer, size_t nbytes)
@@ -120,8 +109,8 @@ writen (int fd, const void *buffer, size_t nbytes)
 }
 
 
-static my_funopen_hook_ret_t 
-fun_writer (void *cookie_arg, const char *buffer, my_funopen_hook_size_t size)
+static ssize_t 
+fun_writer (void *cookie_arg, const void *buffer, size_t size)
 {
   struct fun_cookie_s *cookie = cookie_arg;
 
@@ -191,7 +180,7 @@ fun_writer (void *cookie_arg, const char *buffer, my_funopen_hook_size_t size)
 
   log_socket = cookie->fd;
   if (cookie->fd != -1 && !writen (cookie->fd, buffer, size))
-    return (my_funopen_hook_ret_t)size; /* Okay. */ 
+    return (ssize_t)size; /* Okay. */ 
 
   if (!running_detached && cookie->fd != -1
       && isatty (fileno (stderr)))
@@ -210,9 +199,10 @@ fun_writer (void *cookie_arg, const char *buffer, my_funopen_hook_size_t size)
       log_socket = -1;
     }
 
-  return (my_funopen_hook_ret_t)size;
+  return (ssize_t)size;
 }
 
+
 static int
 fun_closer (void *cookie_arg)
 {
@@ -224,8 +214,6 @@ fun_closer (void *cookie_arg)
   log_socket = -1;
   return 0;
 }
-#endif /*USE_FUNWRITER*/
-
 
 
 /* Common function to either set the logging to a file or a file
@@ -233,17 +221,14 @@ fun_closer (void *cookie_arg)
 static void
 set_file_fd (const char *name, int fd) 
 {
-  FILE *fp;
+  estream_t fp;
   int want_socket;
-#ifdef USE_FUNWRITER
   struct fun_cookie_s *cookie;
-#endif
 
   /* Close an open log stream.  */
   if (logstream)
     {
-      if (logstream != stderr && logstream != stdout)
-        fclose (logstream);
+      es_fclose (logstream);
       logstream = NULL;
     }
 
@@ -266,7 +251,7 @@ set_file_fd (const char *name, int fd)
     }
 
   /* Setup a new stream.  */
-#ifdef USE_FUNWRITER
+
   /* The xmalloc below is justified because we can expect that this
      function is called only during initialization and there is no
      easy way out of this error condition.  */
@@ -288,55 +273,44 @@ set_file_fd (const char *name, int fd)
     }
   log_socket = cookie->fd;
 
-#ifdef HAVE_FOPENCOOKIE
   {
-    cookie_io_functions_t io = { NULL };
-    io.write = fun_writer;
-    io.close = fun_closer;
+    es_cookie_io_functions_t io = { NULL };
+    io.func_write = fun_writer;
+    io.func_close = fun_closer;
     
-    fp = fopencookie (cookie, "w", io);
+    fp = es_fopencookie (cookie, "w", io);
   }
-#else /*!HAVE_FOPENCOOKIE*/
-  fp = funopen (cookie, NULL, fun_writer, NULL, fun_closer);
-#endif /*!HAVE_FOPENCOOKIE*/
-
-#else /*!USE_FUNWRITER*/
-
-  /* The system does not feature custom streams.  Thus fallback to
-     plain stdio. */
-  if (want_socket)
-    {
-      fprintf (stderr, "system does not support logging to a socket - "
-               "using stderr\n");
-      fp = stderr;
-    }
-  else if (name)
-    fp = fopen (name, "a");
-  else if (fd == 1)
-    fp = stdout;
-  else if (fd == 2)
-    fp = stderr;
-  else
-    fp = fdopen (fd, "a");
 
-  log_socket = -1; 
-
-#endif /*!USE_FUNWRITER*/
-
-  /* On error default to stderr.  */
+  /* On error default to a stderr based estream.  */
   if (!fp)
     {
-      if (name)
-        fprintf (stderr, "failed to open log file `%s': %s\n",
-                 name, strerror(errno));
+      fp = es_fpopen (stderr, "a");
+      if (fp)
+        {
+          if (name)
+            es_fprintf (fp, "failed to open log file `%s': %s\n",
+                        name, strerror (errno));
+          else
+            es_fprintf (fp, "failed to fdopen file descriptor %d: %s\n",
+                        fd, strerror (errno));
+        }
       else
-        fprintf (stderr, "failed to fdopen file descriptor %d: %s\n",
-                 fd, strerror(errno));
-      /* We need to make sure that there is a log stream.  We use stderr. */
-      fp = stderr;
+        {
+          fprintf (stderr, "failed to use stderr as log stream: %s\n",
+                   strerror (errno));
+          /* No way to log something.  Create a dummy estream so that
+             there is something we can use.  */
+          fp = es_fpopen (NULL, "a");
+          if (!fp)
+            {
+              fprintf (stderr, "fatal: failed to open dummy stream: %s\n",
+                       strerror (errno));
+              abort();
+            }
+        }
     }
-  else
-    setvbuf (fp, NULL, _IOLBF, 0);
+
+  es_setvbuf (fp, NULL, _IOLBF, 0);
   
   logstream = fp;
 
@@ -412,13 +386,13 @@ log_get_prefix (unsigned int *flags)
 
 /* This function returns true if the file descriptor FD is in use for
    logging.  This is preferable over a test using log_get_fd in that
-   it allows the logging code to use more then one file descriptor. */
+   it allows the logging code to use more then one file descriptor.  */
 int
 log_test_fd (int fd)
 {
   if (logstream)
     {
-      int tmp = fileno (logstream);
+      int tmp = es_fileno (logstream);
       if ( tmp != -1 && tmp == fd)
         return 1;
     }
@@ -430,16 +404,14 @@ log_test_fd (int fd)
 int
 log_get_fd ()
 {
-  return fileno(logstream?logstream:stderr);
+  return logstream? es_fileno(logstream) : -1;
 }
 
-FILE *
+estream_t
 log_get_stream ()
 {
-  /* FIXME: We should not return stderr here but initialize the log
-     stream properly.  This might break more things than using stderr,
-     though */
-  return logstream?logstream:stderr;
+  assert (logstream);
+  return logstream;
 }
 
 static void
@@ -451,8 +423,9 @@ do_logv (int level, const char *fmt, va_list arg_ptr)
       assert (logstream);
     }
 
+  es_flockfile (logstream);
   if (missing_lf && level != JNLIB_LOG_CONT)
-    putc('\n', logstream );
+    es_putc_unlocked ('\n', logstream );
   missing_lf = 0;
 
   if (level != JNLIB_LOG_CONT)
@@ -464,28 +437,28 @@ do_logv (int level, const char *fmt, va_list arg_ptr)
           time_t atime = time (NULL);
           
           tp = localtime (&atime);
-          fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
-                   1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
-                   tp->tm_hour, tp->tm_min, tp->tm_sec );
+          es_fprintf_unlocked (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
+                               1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+                               tp->tm_hour, tp->tm_min, tp->tm_sec );
         }
       if (with_prefix || force_prefixes)
-        fputs (prefix_buffer, logstream);
+        es_fputs_unlocked (prefix_buffer, logstream);
       if (with_pid || force_prefixes)
         {
           if (get_tid_callback)
-            fprintf (logstream, "[%u.%lx]", 
-                     (unsigned int)getpid (), get_tid_callback ());
+            es_fprintf_unlocked (logstream, "[%u.%lx]", 
+                        (unsigned int)getpid (), get_tid_callback ());
           else
-            fprintf (logstream, "[%u]", (unsigned int)getpid ());
+            es_fprintf_unlocked (logstream, "[%u]", (unsigned int)getpid ());
         }
       if (!with_time || force_prefixes)
-        putc (':', logstream);
+        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
-        putc (' ', logstream);
+        es_putc_unlocked (' ', logstream);
     }
 
   switch (level)
@@ -495,38 +468,40 @@ do_logv (int level, const char *fmt, va_list arg_ptr)
     case JNLIB_LOG_INFO: break;
     case JNLIB_LOG_WARN: break;
     case JNLIB_LOG_ERROR: break;
-    case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
-    case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
-    case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
-    default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
+    case JNLIB_LOG_FATAL: es_fputs_unlocked ("Fatal: ",logstream ); break;
+    case JNLIB_LOG_BUG:   es_fputs_unlocked ("Ohhhh jeeee: ", logstream); break;
+    case JNLIB_LOG_DEBUG: es_fputs_unlocked ("DBG: ", logstream ); break;
+    default: 
+      es_fprintf_unlocked (logstream,"[Unknown log level %d]: ", level);
+      break;
     }
 
-
   if (fmt)
     {
-      vfprintf(logstream,fmt,arg_ptr) ;
+      es_vfprintf_unlocked (logstream, fmt, arg_ptr);
       if (*fmt && fmt[strlen(fmt)-1] != '\n')
         missing_lf = 1;
-#ifdef HAVE_W32_SYSTEM
-      else
-        fflush (logstream);
-#endif
     }
 
   if (level == JNLIB_LOG_FATAL)
     {
       if (missing_lf)
-        putc('\n', logstream );
-      exit(2);
+        es_putc_unlocked ('\n', logstream);
+      es_funlockfile (logstream);
+      exit (2);
     }
-  if (level == JNLIB_LOG_BUG)
+  else if (level == JNLIB_LOG_BUG)
     {
       if (missing_lf)
-        putc('\n', logstream );
-      abort();
+        es_putc_unlocked ('\n', logstream );
+      es_funlockfile (logstream);
+      abort ();
     }
+  else
+    es_funlockfile (logstream);
 }
 
+
 static void
 do_log( int level, const char *fmt, ... )
 {
index 0b96108..7f59527 100644 (file)
@@ -1,5 +1,6 @@
 /* logging.h
- * Copyright (C) 1999, 2000, 2001, 2004, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 1999, 2000, 2001, 2004, 2006,
+ *               2010 Free Software Foundation, Inc.
  *
  * This file is part of JNLIB.
  *
@@ -21,6 +22,7 @@
 #define LIBJNLIB_LOGGING_H
 
 #include <stdio.h>
+#include "estream.h"
 #include "mischelp.h"
 
 /* Flag values for log_set_prefix. */
@@ -38,7 +40,7 @@ void log_set_prefix (const char *text, unsigned int flags);
 const char *log_get_prefix (unsigned int *flags);
 int log_test_fd (int fd);
 int  log_get_fd(void);
-FILE *log_get_stream (void);
+estream_t log_get_stream (void);
 
 #ifdef JNLIB_GCC_M_FUNCTION
   void bug_at( const char *file, int line, const char *func ) JNLIB_GCC_A_NR;