Reworked the posix and w32 exechelpers.
authorWerner Koch <wk@gnupg.org>
Fri, 20 Aug 2010 12:18:38 +0000 (12:18 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 20 Aug 2010 12:18:38 +0000 (12:18 +0000)
13 files changed:
ChangeLog
NEWS
README
common/ChangeLog
common/estream.c
common/estream.h
common/exechelp-posix.c
common/exechelp-w32.c
common/exechelp-w32ce.c
common/exechelp.h
tools/ChangeLog
tools/gpgconf-comp.c
tools/gpgconf.c

index c0cf51f..12a1772 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-08-19  Werner Koch  <wk@g10code.com>
+
+       * configure.ac (AH_BOTTOM): Define GPG_ERR_ENABLE_ERRNO_MACROS.
+
 2010-08-09  Werner Koch  <wk@g10code.com>
 
        * configure.ac (inet_pton): Check for it.
diff --git a/NEWS b/NEWS
index 0feecb4..886bebb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,8 @@ Noteworthy changes in version 2.1.x (under development)
 
  * Given sufficient permissions Dirmngr is started automagically.
 
+ * Fixed output of "gpgconf --check-options".
+
 
 Noteworthy changes in version 2.0.13 (2009-09-04)
 -------------------------------------------------
diff --git a/README b/README
index 89be1f0..0626f90 100644 (file)
--- a/README
+++ b/README
@@ -16,7 +16,7 @@ INTRODUCTION
 GnuPG is GNU's tool for secure communication and data storage.  It can
 be used to encrypt data and to create digital signatures.  It includes
 an advanced key management facility and is compliant with the proposed
-OpenPGP Internet standard as described in RFC2440 and the S/MIME
+OpenPGP Internet standard as described in RFC4880 and the S/MIME
 standard as described by several RFCs.
 
 GnuPG is distributed under the terms of the GNU General Public
index f53a192..1fdd7de 100644 (file)
@@ -1,3 +1,31 @@
+2010-08-20  Werner Koch  <wk@g10code.com>
+
+       * exechelp-w32.c (create_inheritable_pipe): Change arg to HANDLE.
+
+       * estream.h (es_sysopen_t): New.
+       * estream.c (es_func_w32_create, es_func_w32_read)
+       (es_func_w32_write, es_func_w32_seek, es_func_w32_destroy)
+       (estream_functions_w32, estream_cookie_fd): New.  Only for W32.
+       (es_sysopen, es_sysopen_nc): New.
+       (do_w32open, do_sysopen): New.
+       (es_syshd, es_syshd_unlocked): New.
+       (struct estream_internal): Replace filed FD by SYSHD.
+       (es_initialize): Clear SYSHD_VALID.
+       (map_w32_to_errno): New.
+       (es_get_fd): Remove.
+       (es_fileno_unlocked): Re-implement using es_syshd.
+       (es_initialize, es_create): Replace arg FD by SYSHD.
+       (es_fopen, es_mopen, es_fopenmem, do_fdopen, do_fpopen)
+       (es_tmpfile): Use SYSHD instead of FD.
+       (es_destroy): Rename to do_close.
+
+2010-08-19  Werner Koch  <wk@g10code.com>
+
+       * exechelp-posix.c (create_pipe_and_estream): New.
+       (gnupg_spawn_process): Rework this function and its calling
+       convention; it is not used anyway.
+       * exechelp-w32.c (gnupg_spawn_process): Ditto.
+
 2010-08-18  Werner Koch  <wk@g10code.com>
 
        * logging.c (writen): Add arg IS_SOCKET.
index ea5d4d0..00f40d2 100644 (file)
@@ -126,9 +126,9 @@ int _setmode (int handle, int mode);
 #endif
 
 #ifdef HAVE_W32_SYSTEM
-# define IS_INVALID_FD(a) ((void*)(a) == (void*)(-1))
+# define IS_INVALID_FD(a)    ((void*)(a) == (void*)(-1)) /* ?? FIXME.  */
 #else
-# define IS_INVALID_FD(a) ((a) == -1)
+# define IS_INVALID_FD(a)    ((a) == -1)
 #endif
 
 
@@ -197,6 +197,7 @@ dummy_mutex_call_int (estream_mutex_t mutex)
 # define ESTREAM_SYS_YIELD() do { } while (0)
 #endif
 
+
 /* Misc definitions.  */
 
 #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
@@ -218,7 +219,7 @@ struct estream_internal
   es_cookie_seek_function_t func_seek;
   es_cookie_close_function_t func_close;
   int strategy;
-  int fd;                        /* Value to return by es_fileno().  */
+  es_syshd_t syshd;              /* A copy of the sytem handle.  */
   struct
   {
     unsigned int err: 1;
@@ -317,7 +318,39 @@ mem_free (void *p)
     free (p);
 }
 
+#ifdef HAVE_W32_SYSTEM
+static int
+map_w32_to_errno (DWORD w32_err)
+{
+  switch (w32_err)
+    {
+    case 0:
+      return 0;
+
+    case ERROR_FILE_NOT_FOUND:
+      return ENOENT;
+
+    case ERROR_PATH_NOT_FOUND:
+      return ENOENT;
+
+    case ERROR_ACCESS_DENIED:
+      return EPERM;
 
+    case ERROR_INVALID_HANDLE:
+    case ERROR_INVALID_BLOCK:
+      return EINVAL;
+
+    case ERROR_NOT_ENOUGH_MEMORY:
+      return ENOMEM;
+      
+    case ERROR_NO_DATA:
+      return EPIPE;
+
+    default:
+      return EIO;
+    }
+}
+#endif /*HAVE_W32_SYSTEM*/
 
 /*
  * List manipulation.
@@ -744,7 +777,7 @@ static es_cookie_io_functions_t estream_functions_mem =
 
 
 \f
-/* Implementation of fd I/O.  */
+/* Implementation of file descriptor based I/O.  */
 
 /* Cookie for fd objects.  */
 typedef struct estream_cookie_fd
@@ -887,6 +920,217 @@ static es_cookie_io_functions_t estream_functions_fd =
 
 
 \f
+#ifdef HAVE_W32_SYSTEM
+/* Implementation of W32 handle based I/O.  */
+
+/* Cookie for fd objects.  */
+typedef struct estream_cookie_w32
+{
+  HANDLE hd;     /* The handle we are using for actual output.  */
+  int no_close;  /* If set we won't close the handle.  */
+} *estream_cookie_w32_t;
+
+
+/* Create function for w32 handle objects.  */
+static int
+es_func_w32_create (void **cookie, HANDLE hd,
+                    unsigned int modeflags, int no_close)
+{
+  estream_cookie_w32_t w32_cookie;
+  int err;
+
+  w32_cookie = mem_alloc (sizeof (*w32_cookie));
+  if (!w32_cookie)
+    err = -1;
+  else
+    {
+      /* CR/LF translations are not supported when using the bare W32
+         API.  If that is really required we need to implemented that
+         in the upper layer.  */
+      (void)modeflags;
+
+      w32_cookie->hd = hd;
+      w32_cookie->no_close = no_close;
+      *cookie = w32_cookie;
+      err = 0;
+    }
+  
+  return err;
+}
+
+/* Read function for W32 handle objects.  */
+static ssize_t
+es_func_w32_read (void *cookie, void *buffer, size_t size)
+{
+  estream_cookie_w32_t w32_cookie = cookie;
+  ssize_t bytes_read;
+  
+  if (w32_cookie->hd == INVALID_HANDLE_VALUE)
+    {
+      ESTREAM_SYS_YIELD ();
+      bytes_read = 0;
+    }
+  else
+    {
+      do
+        {
+#ifdef HAVE_PTH
+          /* Note: Our pth_read actually uses HANDLE! */
+          bytes_read = pth_read ((int)w32_cookie->hd, buffer, size);
+#else
+          DWORD nread, ec;
+          
+          if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL))
+            {
+              ec = GetLastError ();
+              if (ec == ERROR_BROKEN_PIPE)
+                bytes_read = 0; /* Like our pth_read we handle this as EOF.  */
+              else
+                {
+                  _set_errno (map_w32_to_errno (ec));
+                  log_debug ("estream: ReadFile returned %d\n",
+                             (int)GetLastError ());
+                  bytes_read = -1;
+                }
+            }
+          else
+            bytes_read = (int)nread;
+#endif
+        }
+      while (bytes_read == -1 && errno == EINTR);
+    }
+
+  return bytes_read;
+}
+
+/* Write function for W32 handle objects.  */
+static ssize_t
+es_func_w32_write (void *cookie, const void *buffer, size_t size)
+{
+  estream_cookie_w32_t w32_cookie = cookie;
+  ssize_t bytes_written;
+
+  if (w32_cookie->hd == INVALID_HANDLE_VALUE)
+    {
+      ESTREAM_SYS_YIELD ();
+      bytes_written = size; /* Yeah:  Success writing to the bit bucket.  */
+    }
+  else
+    {
+      do
+        {
+#ifdef HAVE_PTH
+          /* Note: Our pth_write actually uses HANDLE! */
+          bytes_written = pth_write ((int)w32_cookie->hd, buffer, size);
+#else
+          DWORD nwritten;
+
+         if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL))
+           {
+             _set_errno (map_w32_to_errno (GetLastError ()));
+             bytes_written = -1;
+           }
+         else
+           bytes_written = (int)nwritten;
+#endif
+        }
+      while (bytes_written == -1 && errno == EINTR);
+    }
+
+  return bytes_written;
+}
+
+/* Seek function for W32 handle objects.  */
+static int
+es_func_w32_seek (void *cookie, off_t *offset, int whence)
+{
+  estream_cookie_w32_t w32_cookie = cookie;
+  DWORD method;
+  LARGE_INTEGER distance, newoff;
+
+  if (w32_cookie->hd == INVALID_HANDLE_VALUE)
+    {
+      _set_errno (ESPIPE);
+      return -1;
+    }
+
+  if (whence == SEEK_SET)
+    {
+      method = FILE_BEGIN;
+      distance.QuadPart = (unsigned long long)(*offset);
+    }
+  else if (whence == SEEK_CUR)
+    {
+      method = FILE_CURRENT;
+      distance.QuadPart = (long long)(*offset);
+    }
+  else if (whence == SEEK_END)
+    {
+      method = FILE_END;
+      distance.QuadPart = (long long)(*offset);
+    }
+  else
+    {
+      _set_errno (EINVAL);
+      return -1;
+    }
+#ifdef HAVE_W32CE_SYSTEM
+# warning need to use SetFilePointer
+#else
+  if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method))
+    {
+      _set_errno (map_w32_to_errno (GetLastError ()));
+      return -1;
+    }
+#endif
+  *offset = (unsigned long long)newoff.QuadPart;
+  return 0;
+}
+
+/* Destroy function for W32 handle objects.  */
+static int
+es_func_w32_destroy (void *cookie)
+{
+  estream_cookie_w32_t w32_cookie = cookie;
+  int err;
+
+  if (w32_cookie)
+    {
+      if (w32_cookie->hd == INVALID_HANDLE_VALUE)
+        err = 0;
+      else if (w32_cookie->no_close)
+        err = 0;
+      else
+        { 
+          if (!CloseHandle (w32_cookie->hd))
+            {
+             _set_errno (map_w32_to_errno (GetLastError ()));
+              err = -1;
+            }
+          else
+            err = 0;
+        }
+      mem_free (w32_cookie);
+    }
+  else
+    err = 0;
+
+  return err;
+}
+
+
+static es_cookie_io_functions_t estream_functions_w32 =
+  {
+    es_func_w32_read,
+    es_func_w32_write,
+    es_func_w32_seek,
+    es_func_w32_destroy
+  };
+#endif /*HAVE_W32_SYSTEM*/
+
+
+
+\f
 /* Implementation of FILE* I/O.  */
 
 /* Cookie for fp objects.  */
@@ -1049,7 +1293,7 @@ static es_cookie_io_functions_t estream_functions_fp =
 \f
 /* Implementation of file I/O.  */
 
-/* Create function for file objects.  */
+/* Create function for fd objects.  */
 static int
 es_func_file_create (void **cookie, int *filedes,
                     const char *path, unsigned int modeflags)
@@ -1269,7 +1513,8 @@ es_empty (estream_t stream)
 /* Initialize STREAM.  */
 static void
 es_initialize (estream_t stream,
-              void *cookie, int fd, es_cookie_io_functions_t functions,
+              void *cookie, es_syshd_t *syshd,
+               es_cookie_io_functions_t functions,
                unsigned int modeflags)
 {
   stream->intern->cookie = cookie;
@@ -1280,7 +1525,7 @@ es_initialize (estream_t stream,
   stream->intern->func_seek = functions.func_seek;
   stream->intern->func_close = functions.func_close;
   stream->intern->strategy = _IOFBF;
-  stream->intern->fd = fd;
+  stream->intern->syshd = *syshd;
   stream->intern->print_ntotal = 0;
   stream->intern->indicators.err = 0;
   stream->intern->indicators.eof = 0;
@@ -1329,7 +1574,7 @@ es_deinitialize (estream_t stream)
 
 /* Create a new stream object, initialize it.  */
 static int
-es_create (estream_t *stream, void *cookie, int fd,
+es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
           es_cookie_io_functions_t functions, unsigned int modeflags,
            int with_locked_list)
 {
@@ -1361,7 +1606,7 @@ es_create (estream_t *stream, void *cookie, int fd,
   stream_new->intern = stream_internal_new;
 
   ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
-  es_initialize (stream_new, cookie, fd, functions, modeflags);
+  es_initialize (stream_new, cookie, syshd, functions, modeflags);
 
   err = es_list_add (stream_new, with_locked_list);
   if (err)
@@ -1385,9 +1630,9 @@ es_create (estream_t *stream, void *cookie, int fd,
 
 /* Deinitialize a stream object and destroy it.  */
 static int
-es_destroy (estream_t stream, int with_locked_list)
+do_close (estream_t stream, int with_locked_list)
 {
-  int err = 0;
+  int err;
 
   if (stream)
     {
@@ -1396,6 +1641,8 @@ es_destroy (estream_t stream, int with_locked_list)
       mem_free (stream->intern);
       mem_free (stream);
     }
+  else
+    err = 0;
 
   return err;
 }
@@ -1897,6 +2144,7 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
   unsigned char *data;
   size_t data_len;
   int err;
+  es_syshd_t syshd;
 
   line_new = NULL;
   line_stream = NULL;
@@ -1910,7 +2158,8 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
   if (err)
     goto out;
 
-  err = es_create (&line_stream, line_stream_cookie, -1,
+  memset (&syshd, 0, sizeof syshd);
+  err = es_create (&line_stream, line_stream_cookie, &syshd,
                   estream_functions_mem, O_RDWR, 0);
   if (err)
     goto out;
@@ -1996,7 +2245,7 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
  out:
 
   if (line_stream)
-    es_destroy (line_stream, 0);
+    do_close (line_stream, 0);
   else if (line_stream_cookie)
     es_func_mem_destroy (line_stream_cookie);
 
@@ -2152,12 +2401,6 @@ es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
 }
 
 
-static int
-es_get_fd (estream_t stream)
-{
-  return stream->intern->fd;
-}
-
 \f
 
 /* API.  */
@@ -2172,6 +2415,8 @@ es_init (void)
   return err;
 }
 
+
+\f
 estream_t
 es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
 {
@@ -2181,6 +2426,7 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
   void *cookie;
   int err;
   int fd;
+  es_syshd_t syshd;
 
   stream = NULL;
   cookie = NULL;
@@ -2193,9 +2439,12 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
   err = es_func_file_create (&cookie, &fd, path, modeflags);
   if (err)
     goto out;
+  
+  syshd.type = ES_SYSHD_FD;
+  syshd.u.fd = fd;
 
   create_called = 1;
-  err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags, 0);
+  err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, 0);
   if (err)
     goto out;
 
@@ -2211,6 +2460,7 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
 }
 
 
+\f
 estream_t
 es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
          unsigned int grow,
@@ -2222,6 +2472,7 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
   estream_t stream;
   void *cookie;
   int err;
+  es_syshd_t syshd;
 
   cookie = 0;
   stream = NULL;
@@ -2237,8 +2488,10 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
   if (err)
     goto out;
   
+  memset (&syshd, 0, sizeof syshd);
   create_called = 1;
-  err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags, 0);
+  err = es_create (&stream, cookie, &syshd,
+                   estream_functions_mem, modeflags, 0);
 
  out:
 
@@ -2249,12 +2502,14 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
 }
 
 
+\f
 estream_t
 es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
 {
   unsigned int modeflags;
   estream_t stream = NULL;
   void *cookie = NULL;
+  es_syshd_t syshd;
 
   /* Memory streams are always read/write.  We use MODE only to get
      the append flag.  */
@@ -2269,14 +2524,15 @@ es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
                           memlimit))
     return NULL;
   
-  if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags, 0))
+  memset (&syshd, 0, sizeof syshd);
+  if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, 0))
     (*estream_functions_mem.func_close) (cookie);
 
   return stream;
 }
 
 
-
+\f
 estream_t
 es_fopencookie (void *ES__RESTRICT cookie,
                const char *ES__RESTRICT mode,
@@ -2285,6 +2541,7 @@ es_fopencookie (void *ES__RESTRICT cookie,
   unsigned int modeflags;
   estream_t stream;
   int err;
+  es_syshd_t syshd;
 
   stream = NULL;
   modeflags = 0;
@@ -2293,16 +2550,17 @@ es_fopencookie (void *ES__RESTRICT cookie,
   if (err)
     goto out;
 
-  err = es_create (&stream, cookie, -1, functions, modeflags, 0);
+  memset (&syshd, 0, sizeof syshd);
+  err = es_create (&stream, cookie, &syshd, functions, modeflags, 0);
   if (err)
     goto out;
 
  out:
-
   return stream;
 }
 
 
+\f
 estream_t
 do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
 {
@@ -2311,6 +2569,7 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
   estream_t stream;
   void *cookie;
   int err;
+  es_syshd_t syshd;
 
   stream = NULL;
   cookie = NULL;
@@ -2324,12 +2583,13 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
   if (err)
     goto out;
 
+  syshd.type = ES_SYSHD_FD;
+  syshd.u.fd = filedes;
   create_called = 1;
-  err = es_create (&stream, cookie, filedes, estream_functions_fd,
+  err = es_create (&stream, cookie, &syshd, estream_functions_fd,
                    modeflags, with_locked_list);
 
  out:
-
   if (err && create_called)
     (*estream_functions_fd.func_close) (cookie);
 
@@ -2350,6 +2610,7 @@ es_fdopen_nc (int filedes, const char *mode)
 }
 
 
+\f
 estream_t
 do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
 {
@@ -2358,6 +2619,7 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
   estream_t stream;
   void *cookie;
   int err;
+  es_syshd_t syshd;
 
   stream = NULL;
   cookie = NULL;
@@ -2372,9 +2634,11 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
   err = es_func_fp_create (&cookie, fp, modeflags, no_close);
   if (err)
     goto out;
-  
+
+  syshd.type = ES_SYSHD_FD;
+  syshd.u.fd = fp? fileno (fp): -1;
   create_called = 1;
-  err = es_create (&stream, cookie, fp? fileno (fp):-1, estream_functions_fp,
+  err = es_create (&stream, cookie, &syshd, estream_functions_fp,
                    modeflags, with_locked_list);
 
  out:
@@ -2409,6 +2673,87 @@ es_fpopen_nc (FILE *fp, const char *mode)
 }
 
 
+\f
+#ifdef HAVE_W32_SYSTEM
+estream_t
+do_w32open (HANDLE hd, const char *mode,
+            int no_close, int with_locked_list)
+{
+  unsigned int modeflags;
+  int create_called = 0;
+  estream_t stream = NULL;
+  void *cookie = NULL;
+  int err;
+  es_syshd_t syshd;
+
+  err = es_convert_mode (mode, &modeflags);
+  if (err)
+    goto leave;
+
+  err = es_func_w32_create (&cookie, hd, modeflags, no_close);
+  if (err)
+    goto leave;
+
+  syshd.type = ES_SYSHD_HANDLE;
+  syshd.u.handle = hd;
+  create_called = 1;
+  err = es_create (&stream, cookie, &syshd, estream_functions_w32,
+                   modeflags, with_locked_list);
+
+ leave:
+  if (err && create_called)
+    (*estream_functions_w32.func_close) (cookie);
+
+  return stream;
+}
+#endif /*HAVE_W32_SYSTEM*/
+
+static estream_t
+do_sysopen (es_syshd_t *syshd, const char *mode, int no_close)
+{
+  estream_t stream;
+
+  switch (syshd->type)
+    {
+    case ES_SYSHD_FD:
+    case ES_SYSHD_SOCK:
+      stream = do_fdopen (syshd->u.fd, mode, no_close, 0);
+      break;
+      
+#ifdef HAVE_W32_SYSTEM
+    case ES_SYSHD_HANDLE:
+      stream = do_w32open (syshd->u.handle, mode, no_close, 0);
+      break;
+#endif
+
+    /* FIXME: Support RVIDs under Wince?  */
+
+    default:
+      _set_errno (EINVAL);
+      stream = NULL;
+    }
+  return stream;
+}
+
+/* On POSIX systems this function is an alias for es_fdopen.  Under
+   Windows it uses the bare W32 API and thus a HANDLE instead of a
+   file descriptor.  */
+estream_t
+es_sysopen (es_syshd_t *syshd, const char *mode)
+{
+  return do_sysopen (syshd, mode, 0);
+}
+
+/* Same as es_sysopen but the handle/fd will not be closed by
+   es_fclose.  */
+estream_t
+es_sysopen_nc (es_syshd_t *syshd, const char *mode)
+{
+  return do_sysopen (syshd, mode, 1);
+}
+
+
+
 /* Set custom standard descriptors to be used for stdin, stdout and
    stderr.  This function needs to be called before any of the
    standard streams are accessed.  */
@@ -2500,6 +2845,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
       int create_called;
       void *cookie;
       int fd;
+      es_syshd_t syshd;
 
       cookie = NULL;
       create_called = 0;
@@ -2516,8 +2862,10 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
       if (err)
        goto leave;
 
+      syshd.type = ES_SYSHD_FD;
+      syshd.u.fd = fd;
       create_called = 1;
-      es_initialize (stream, cookie, fd, estream_functions_fd, modeflags);
+      es_initialize (stream, cookie, &syshd, estream_functions_fd, modeflags);
 
     leave:
 
@@ -2526,7 +2874,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
          if (create_called)
            es_func_fd_destroy (cookie);
       
-         es_destroy (stream, 0);
+         do_close (stream, 0);
          stream = NULL;
        }
       else
@@ -2541,7 +2889,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
       /* FIXME?  We don't support re-opening at the moment.  */
       _set_errno (EINVAL);
       es_deinitialize (stream);
-      es_destroy (stream, 0);
+      do_close (stream, 0);
       stream = NULL;
     }
 
@@ -2554,15 +2902,47 @@ es_fclose (estream_t stream)
 {
   int err;
 
-  err = es_destroy (stream, 0);
+  err = do_close (stream, 0);
 
   return err;
 }
 
+
 int
 es_fileno_unlocked (estream_t stream)
 {
-  return es_get_fd (stream);
+  es_syshd_t syshd;
+
+  if (es_syshd (stream, &syshd))
+    return -1;
+  switch (syshd.type)
+    {
+    case ES_SYSHD_FD:   return syshd.u.fd;
+    case ES_SYSHD_SOCK: return syshd.u.sock;
+    default: 
+      _set_errno (EINVAL);
+      return -1;
+    }
+}
+
+
+/* Return the handle of a stream which has been opened by es_sysopen.
+   The caller needs to pass a structure which will be filled with the
+   sys handle.  Return 0 on success or true on error and sets errno.
+   This is the unlocked version.  */
+int
+es_syshd_unlocked (estream_t stream, es_syshd_t *syshd)
+{
+  if (!stream || !syshd || stream->intern->syshd.type == ES_SYSHD_NONE)
+    {
+      if (syshd)
+        syshd->type = ES_SYSHD_NONE;
+      _set_errno (EINVAL);
+      return -1;
+    }
+  
+  *syshd = stream->intern->syshd;
+  return 0;
 }
 
 
@@ -2600,6 +2980,23 @@ es_fileno (estream_t stream)
 }
 
 
+/* Return the handle of a stream which has been opened by es_sysopen.
+   The caller needs to pass a structure which will be filled with the
+   sys handle.  Return 0 on success or true on error and sets errno.
+   This is the unlocked version.  */
+int
+es_syshd (estream_t stream, es_syshd_t *syshd)
+{
+  int ret;
+
+  ESTREAM_LOCK (stream);
+  ret = es_syshd_unlocked (stream, syshd);
+  ESTREAM_UNLOCK (stream);
+
+  return ret;
+}
+
+
 int
 es_feof_unlocked (estream_t stream)
 {
@@ -3371,6 +3768,7 @@ es_tmpfile (void)
   void *cookie;
   int err;
   int fd;
+  es_syshd_t syshd;
 
   create_called = 0;
   stream = NULL;
@@ -3388,11 +3786,12 @@ es_tmpfile (void)
   if (err)
     goto out;
 
+  syshd.type = ES_SYSHD_FD;
+  syshd.u.fd = fd;
   create_called = 1;
-  err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags, 0);
+  err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, 0);
 
  out:
-
   if (err)
     {
       if (create_called)
index 34ff5ce..c5dc19c 100644 (file)
@@ -78,6 +78,8 @@
 #define es_fopenmem           _ESTREAM_PREFIX(es_fopenmem)
 #define es_fdopen             _ESTREAM_PREFIX(es_fdopen)
 #define es_fdopen_nc          _ESTREAM_PREFIX(es_fdopen_nc)
+#define es_sysopen            _ESTREAM_PREFIX(es_sysopen)
+#define es_sysopen_nc         _ESTREAM_PREFIX(es_sysopen_nc)
 #define es_fpopen             _ESTREAM_PREFIX(es_fpopen)
 #define es_fpopen_nc          _ESTREAM_PREFIX(es_fpopen_nc)
 #define _es_set_std_fd        _ESTREAM_PREFIX(_es_set_std_fd)
@@ -211,6 +213,29 @@ typedef struct es_cookie_io_functions
   es_cookie_close_function_t func_close;
 } es_cookie_io_functions_t;
 
+
+enum es_syshd_types 
+  {
+    ES_SYSHD_NONE,  /* No system handle available.  */
+    ES_SYSHD_FD,    /* A file descriptor as returned by open().  */
+    ES_SYSHD_SOCK,  /* A socket as returned by socket().        */
+    ES_SYSHD_RVID,  /* A rendevous id (see libassuan's gpgcedev.c).  */
+    ES_SYSHD_HANDLE /* A HANDLE object (Windows).  */
+  };
+
+typedef struct
+{
+  enum es_syshd_types type;
+  union {
+    int fd;
+    int sock;
+    int rvid;
+    void *handle;
+  } u;
+} es_syshd_t;
+
+
+
 \f
 #ifndef _ESTREAM_GCC_A_PRINTF
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
@@ -245,6 +270,8 @@ estream_t es_mopen (unsigned char *ES__RESTRICT data,
 estream_t es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode);
 estream_t es_fdopen (int filedes, const char *mode);
 estream_t es_fdopen_nc (int filedes, const char *mode);
+estream_t es_sysopen (es_syshd_t *syshd, const char *mode);
+estream_t es_sysopen_nc (es_syshd_t *syshd, const char *mode);
 estream_t es_fpopen (FILE *fp, const char *mode);
 estream_t es_fpopen_nc (FILE *fp, const char *mode);
 estream_t es_freopen (const char *ES__RESTRICT path,
@@ -256,6 +283,8 @@ estream_t es_fopencookie (void *ES__RESTRICT cookie,
 int es_fclose (estream_t stream);
 int es_fileno (estream_t stream);
 int es_fileno_unlocked (estream_t stream);
+int es_syshd (estream_t stream, es_syshd_t *syshd);
+int es_syshd_unlocked (estream_t stream, es_syshd_t *syshd);
 
 void _es_set_std_fd (int no, int fd);
 estream_t _es_get_std_stream (int fd);
index 5a8e028..6ffc562 100644 (file)
@@ -299,45 +299,95 @@ gnupg_create_outbound_pipe (int filedes[2])
 }
 
 
+
+static gpg_error_t
+create_pipe_and_estream (int filedes[2], estream_t *r_fp,
+                         gpg_err_source_t errsource)
+{
+  gpg_error_t err;
+
+  if (pipe (filedes) == -1)
+    {
+      err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+      log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+      filedes[0] = filedes[1] = -1;
+      *r_fp = NULL;
+      return err;
+    }
+
+  *r_fp = es_fdopen (filedes[0], "r");
+  if (!*r_fp)
+    {
+      err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+      log_error (_("error creating a stream for a pipe: %s\n"),
+                 gpg_strerror (err));
+      close (filedes[0]);
+      close (filedes[1]);
+      filedes[0] = filedes[1] = -1;
+      return err;
+    }
+  return 0;
+}
+  
+
+
 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     estream_t infile, estream_t outfile,
+                     gpg_err_source_t errsource,
                      void (*preexec)(void), unsigned int flags,
-                     estream_t *statusfile, pid_t *pid)
+                     estream_t infp,
+                     estream_t *r_outfp,
+                     estream_t *r_errfp,
+                     pid_t *pid)
 {
   gpg_error_t err;
-  int fd, fdout, rp[2];
+  int infd = -1;
+  int outpipe[2] = {-1, -1};
+  int errpipe[2] = {-1, -1};
+  estream_t outfp = NULL;
+  estream_t errfp = NULL;
 
   (void)flags; /* Currently not used.  */
 
-  *statusfile = NULL;
-  *pid = (pid_t)(-1);
+  if (r_outfp)
+    *r_outfp = NULL;
+  if (r_errfp)
+    *r_errfp = NULL;
+  *pid = (pid_t)(-1); /* Always required.  */
 
-  if (infile)
+  if (infp)
     {
-      es_fflush (infile);
-      es_rewind (infile);
-      fd = es_fileno (infile);
+      es_fflush (infp);
+      es_rewind (infp);
+      infd = es_fileno (infp);
+      if (infd == -1)
+        return gpg_err_make (errsource, GPG_ERR_INV_VALUE);
     }
-  else
-    fd = -1;
 
-  if (outfile)
-    fdout = es_fileno (outfile);
-  else
-    fdout = -1;
-
-  if ((infile && fd == -1) || (outfile && fdout == -1))
-    log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
+  if (r_outfp)
+    {
+      err = create_pipe_and_estream (outpipe, &outfp, errsource);
+      if (err)
+        return err;
+    }
 
-  if (pipe (rp) == -1)
+  if (r_errfp)
     {
-      err = gpg_error_from_syserror ();
-      log_error (_("error creating a pipe: %s\n"), strerror (errno));
-      return err;
+      err = create_pipe_and_estream (errpipe, &errfp, errsource);
+      if (err)
+        {
+          if (outfp)
+            es_fclose (outfp);
+          else if (outpipe[0] != -1)
+            close (outpipe[0]);
+          if (outpipe[1] != -1)
+            close (outpipe[1]);
+          return err;
+        }
     }
 
+
 #ifdef USE_GNU_PTH      
   *pid = pth_fork? pth_fork () : fork ();
 #else
@@ -345,33 +395,45 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
 #endif
   if (*pid == (pid_t)(-1))
     {
-      err = gpg_error_from_syserror ();
-      log_error (_("error forking process: %s\n"), strerror (errno));
-      close (rp[0]);
-      close (rp[1]);
+      err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+      log_error (_("error forking process: %s\n"), gpg_strerror (err));
+
+      if (outfp)
+        es_fclose (outfp);
+      else if (outpipe[0] != -1)
+        close (outpipe[0]);
+      if (outpipe[1] != -1)
+        close (outpipe[1]);
+
+      if (errfp)
+        es_fclose (errfp);
+      else if (errpipe[0] != -1)
+        close (errpipe[0]);
+      if (errpipe[1] != -1)
+        close (errpipe[1]);
       return err;
     }
 
   if (!*pid)
     { 
+      /* This is the child. */
       gcry_control (GCRYCTL_TERM_SECMEM);
-      /* Run child. */
-      do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
+      es_fclose (outfp);
+      es_fclose (errfp);
+      do_exec (pgmname, argv, infd, outpipe[1], errpipe[1], preexec);
       /*NOTREACHED*/
     }
 
-  /* Parent. */
-  close (rp[1]);
+  /* This is the parent. */
+  if (outpipe[1] != -1)
+    close (outpipe[1]);
+  if (errpipe[1] != -1)
+    close (errpipe[1]);
 
-  *statusfile = es_fdopen (rp[0], "r");
-  if (!*statusfile)
-    {
-      err = gpg_error_from_syserror ();
-      log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
-      kill (*pid, SIGTERM);
-      *pid = (pid_t)(-1);
-      return err;
-    }
+  if (r_outfp)
+    *r_outfp = outfp;
+  if (r_errfp)
+    *r_errfp = errfp;
 
   return 0;
 }
index 297f6f8..13f6007 100644 (file)
@@ -257,7 +257,7 @@ build_w32_commandline (const char *pgmname, const char * const *argv,
 /* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
    the read end is inheritable, with 1 the write end is inheritable.  */
 static int
-create_inheritable_pipe (int filedes[2], int inherit_idx)
+create_inheritable_pipe (HANDLE filedes[2], int inherit_idx)
 {
   HANDLE r, w, h;
   SECURITY_ATTRIBUTES sec_attr;
@@ -290,8 +290,8 @@ create_inheritable_pipe (int filedes[2], int inherit_idx)
       r = h;
     }
 
-  filedes[0] = handle_to_fd (r);
-  filedes[1] = handle_to_fd (w);
+  filedes[0] = r;
+  filedes[1] = w;
   return 0;
 }
 
@@ -315,27 +315,27 @@ static gpg_error_t
 do_create_pipe (int filedes[2], int inherit_idx)
 {
   gpg_error_t err = 0;
-  int fds[2];
+  HANDLE fds[2];
 
   filedes[0] = filedes[1] = -1;
   err = gpg_error (GPG_ERR_GENERAL);
   if (!create_inheritable_pipe (fds, inherit_idx))
     {
-      filedes[0] = _open_osfhandle (fds[0], 0);
+      filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), 0);
       if (filedes[0] == -1)
         {
-          log_error ("failed to translate osfhandle %p\n", (void*)fds[0]);
-          CloseHandle (fd_to_handle (fds[1]));
+          log_error ("failed to translate osfhandle %p\n", fds[0]);
+          CloseHandle (fds[1]);
         }
       else 
         {
-          filedes[1] = _open_osfhandle (fds[1], 1);
+          filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), 1);
           if (filedes[1] == -1)
             {
-              log_error ("failed to translate osfhandle %p\n", (void*)fds[1]);
+              log_error ("failed to translate osfhandle %p\n", fds[1]);
               close (filedes[0]);
               filedes[0] = -1;
-              CloseHandle (fd_to_handle (fds[1]));
+              CloseHandle (fds[1]);
             }
           else
             err = 0;
@@ -365,9 +365,12 @@ gnupg_create_outbound_pipe (int filedes[2])
 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     estream_t infile, estream_t outfile,
+                     gpg_err_source_t errsource,
                      void (*preexec)(void), unsigned int flags,
-                     estream_t *statusfile, pid_t *pid)
+                     estream_t infp,
+                     estream_t *r_outfp,
+                     estream_t *r_errfp,
+                     pid_t *pid)
 {
   gpg_error_t err;
   SECURITY_ATTRIBUTES sec_attr;
@@ -381,32 +384,103 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
   STARTUPINFO si;
   int cr_flags;
   char *cmdline;
-  int fd, fdout, rp[2];
-  HANDLE nullhd[2];
+  HANDLE inhandle = INVALID_HANDLE_VALUE;
+  HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+  HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
+  estream_t outfp = NULL;
+  estream_t errfp = NULL;
+  HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
+                      INVALID_HANDLE_VALUE,
+                      INVALID_HANDLE_VALUE};
   int i;
+  es_syshd_t syshd;
 
-  (void)preexec;
-
-  /* Setup return values.  */
-  *statusfile = NULL;
-  *pid = (pid_t)(-1);
+  if (r_outfp)
+    *r_outfp = NULL;
+  if (r_errfp)
+    *r_errfp = NULL;
+  *pid = (pid_t)(-1); /* Always required.  */
   
-  if (infile)
+  if (infp)
     {
-      es_fflush (infile);
-      es_rewind (infile);
-      fd = _get_osfhandle (es_fileno (infile));
+      es_fflush (infp);
+      es_rewind (infp);
+      es_syshd (infp, &syshd);
+      switch (syshd.type)
+        {
+        case ES_SYSHD_FD:
+          inhandle = (HANDLE)_get_osfhandle (syshd.u.fd);
+          break;
+        case ES_SYSHD_SOCK:
+          inhandle = (HANDLE)_get_osfhandle (syshd.u.sock);
+          break;
+        case ES_SYSHD_HANDLE:
+          inhandle = syshd.u.handle;
+          break;
+        default:
+          inhandle = INVALID_HANDLE_VALUE;
+          break;
+        }      
+      if (inhandle == INVALID_HANDLE_VALUE)
+        return gpg_err_make (errsource, GPG_ERR_INV_VALUE);
+      /* FIXME: In case we can't get a system handle (e.g. due to
+         es_fopencookie we should create a piper and a feeder
+         thread.  */
     }
-  else
-    fd = -1;
 
-  if (outfile)
-    fdout = _get_osfhandle (es_fileno (outfile));
-  else
-    fdout = -1;
+  if (r_outfp)
+    {
+      if (create_inheritable_pipe (outpipe, 1))
+        {
+          err = gpg_err_make (errsource, GPG_ERR_GENERAL);
+          log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+          return err;
+        }
 
-  if ( (infile && fd == -1) || (outfile && fdout == -1))
-    log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
+      syshd.type = ES_SYSHD_HANDLE;
+      syshd.u.handle = outpipe[0];
+      outfp = es_sysopen (&syshd, "r");
+      if (!outfp)
+        {
+          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+          log_error (_("error creating a stream for a pipe: %s\n"),
+                     gpg_strerror (err));
+          CloseHandle (outpipe[0]);
+          CloseHandle (outpipe[1]);
+          outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
+          return err;
+        }
+    }
+
+  if (r_errfp)
+    {
+      if (create_inheritable_pipe (errpipe, 1))
+        {
+          err = gpg_err_make (errsource, GPG_ERR_GENERAL);
+          log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
+          return err;
+        }
+
+      syshd.type = ES_SYSHD_HANDLE;
+      syshd.u.handle = errpipe[0];
+      errfp = es_sysopen (&syshd, "r");
+      if (!errfp)
+        {
+          err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
+          log_error (_("error creating a stream for a pipe: %s\n"),
+                     gpg_strerror (err));
+          CloseHandle (errpipe[0]);
+          CloseHandle (errpipe[1]);
+          errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
+          if (outfp)
+            es_fclose (outfp);
+          else if (outpipe[0] != INVALID_HANDLE_VALUE)
+            CloseHandle (outpipe[0]);
+          if (outpipe[1] != INVALID_HANDLE_VALUE)
+            CloseHandle (outpipe[1]);
+          return err;
+        }
+    }
 
   /* Prepare security attributes.  */
   memset (&sec_attr, 0, sizeof sec_attr );
@@ -418,27 +492,24 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
   if (err)
     return err; 
 
-  /* Create a pipe.  */
-  if (create_inheritable_pipe (rp, 1))
-    {
-      err = gpg_error (GPG_ERR_GENERAL);
-      log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
-      xfree (cmdline);
-      return err;
-    }
-  
-  nullhd[0] =    fd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
-  nullhd[1] = fdout == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
+  if (inhandle != INVALID_HANDLE_VALUE)
+    nullhd[0] = w32_open_null (0);
+  if (outpipe[1] != INVALID_HANDLE_VALUE)
+    nullhd[1] = w32_open_null (0);
+  if (errpipe[1] != INVALID_HANDLE_VALUE)
+    nullhd[2] = w32_open_null (0);
 
   /* Start the process.  Note that we can't run the PREEXEC function
-     because this would change our own environment. */
+     because this might change our own environment. */
+  (void)preexec;
+
   memset (&si, 0, sizeof si);
   si.cb = sizeof (si);
   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
-  si.hStdInput  =    fd == -1? nullhd[0] : fd_to_handle (fd);
-  si.hStdOutput = fdout == -1? nullhd[1] : fd_to_handle (fdout);
-  si.hStdError  = fd_to_handle (rp[1]);
+  si.hStdInput  =   inhandle == INVALID_HANDLE_VALUE? nullhd[0] : inhandle;
+  si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
+  si.hStdError  = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
 
   cr_flags = (CREATE_DEFAULT_ERROR_MODE
               | ((flags & 128)? DETACHED_PROCESS : 0)
@@ -459,9 +530,19 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
     {
       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
       xfree (cmdline);
-      CloseHandle (fd_to_handle (rp[0]));
-      CloseHandle (fd_to_handle (rp[1]));
-      return gpg_error (GPG_ERR_GENERAL);
+      if (outfp)
+        es_fclose (outfp);
+      else if (outpipe[0] != INVALID_HANDLE_VALUE)
+        CloseHandle (outpipe[0]);
+      if (outpipe[1] != INVALID_HANDLE_VALUE)
+        CloseHandle (outpipe[1]);
+      if (errfp)
+        es_fclose (errfp);
+      else if (errpipe[0] != INVALID_HANDLE_VALUE)
+        CloseHandle (errpipe[0]);
+      if (errpipe[1] != INVALID_HANDLE_VALUE)
+        CloseHandle (errpipe[1]);
+      return gpg_err_make (errsource, GPG_ERR_GENERAL);
     }
   xfree (cmdline);
   cmdline = NULL;
@@ -471,17 +552,21 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
     if (nullhd[i] != INVALID_HANDLE_VALUE)
       CloseHandle (nullhd[i]);
 
-  /* Close the other end of the pipe.  */
-  CloseHandle (fd_to_handle (rp[1]));
-  
-/*   log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
-/*              " dwProcessID=%d dwThreadId=%d\n", */
-/*              pi.hProcess, pi.hThread, */
-/*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
+  /* Close the inherited ends of the pipes.  */
+  if (outpipe[1] != INVALID_HANDLE_VALUE)
+    CloseHandle (outpipe[1]);
+  if (errpipe[1] != INVALID_HANDLE_VALUE)
+    CloseHandle (errpipe[1]);
   
+  /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
+  /*            " dwProcessID=%d dwThreadId=%d\n", */
+  /*            pi.hProcess, pi.hThread, */
+  /*            (int) pi.dwProcessId, (int) pi.dwThreadId); */
+  /* log_debug ("                     outfp=%p errfp=%p\n", outfp, errfp); */
+
   /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
-     invalid argument error if we pass the correct processID to
-     it.  As a workaround we use -1 (ASFW_ANY).  */
+     invalid argument error if we pass it the correct processID.  As a
+     workaround we use -1 (ASFW_ANY).  */
   if ( (flags & 64) )
     gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
 
@@ -489,22 +574,10 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
   ResumeThread (pi.hThread);
   CloseHandle (pi.hThread); 
 
-  {
-    int x;
-
-    x = _open_osfhandle (rp[0], 0);
-    if (x == -1)
-      log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
-    else 
-      *statusfile = es_fdopen (x, "r");
-  }
-  if (!*statusfile)
-    {
-      err = gpg_error_from_syserror ();
-      log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
-      CloseHandle (pi.hProcess);
-      return err;
-    }
+  if (r_outfp)
+    *r_outfp = outfp;
+  if (r_errfp)
+    *r_errfp = errfp;
 
   *pid = handle_to_pid (pi.hProcess);
   return 0;
index 5a84c9f..f49a442 100644 (file)
@@ -83,7 +83,7 @@ struct feeder_thread_parms
 };
 
 
-/* The thread started by start_feeded.  */
+/* The thread started by start_feede3.  */
 static void *
 feeder_thread (void *arg)
 {
@@ -485,10 +485,14 @@ create_process (const char *pgmname, const char *cmdline,
 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     estream_t infile, estream_t outfile,
+                     gpg_err_source_t errsource,
                      void (*preexec)(void), unsigned int flags,
-                     estream_t *statusfile, pid_t *pid)
+                     estream_t infp,
+                     estream_t *r_outfp,
+                     estream_t *r_errfp,
+                     pid_t *pid)
 {
+#if 0
   gpg_error_t err;
   PROCESS_INFORMATION pi = {NULL };
   char *cmdline;
@@ -598,7 +602,9 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
 
   *pid = handle_to_pid (pi.hProcess);
   return 0;
-
+#else
+  return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
+#endif
 }
 
 
index 3a5b9e2..e6a0ee5 100644 (file)
@@ -52,15 +52,24 @@ gpg_error_t gnupg_create_inbound_pipe (int filedes[2]);
 gpg_error_t gnupg_create_outbound_pipe (int filedes[2]);
 
 
-/* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
-   stdin, write the output to OUTFILE.  INFILE or PUTFILE may be NULL
-   to connect thenm to /dev/null.  Returns a new stream in STATUSFILE
-   for stderr and the pid of the process in PID. The arguments for the
-   process are expected in the NULL terminated array ARGV.  The
-   program name itself should not be included there.  If PREEXEC is
-   not NULL, that function will be called right before the exec.
-   Calling gnupg_wait_process and gnupg_release_process is required.
-   Returns 0 on success or an error code.
+/* Fork and exec the PGMNAME.  If INFP is NULL connect /dev/null to
+   stdin of the new process; if it is not NULL connect the file
+   descriptor retrieved from INFP to stdin.  If R_OUTFP is NULL
+   connect stdout of the new process to /dev/null; if it is not NULL
+   store the address of a pointer to a new estream there.  If R_ERRFP
+   is NULL connect stderr of the new process to /dev/null; if it is
+   not NULL store the address of a pointer to a new estream there.  On
+   success the pid of the new process is stored at PID.  On error -1
+   is stored at PID and if R_OUTFP or R_ERRFP are not NULL, NULL is
+   stored there.
+
+   The arguments for the process are expected in the NULL terminated
+   array ARGV.  The program name itself should not be included there.
+   If PREEXEC is not NULL, the given function will be called right
+   before the exec. 
+
+   Returns 0 on success or an error code.  Calling gnupg_wait_process
+   and gnupg_release_process is required if the function succeeded.
 
    FLAGS is a bit vector:
 
@@ -74,10 +83,14 @@ gpg_error_t gnupg_create_outbound_pipe (int filedes[2]);
           allows SetForegroundWindow for all childs of this process.
 
  */
-gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[],
-                                 estream_t infile, estream_t outfile,
-                                 void (*preexec)(void), unsigned int flags,
-                                 estream_t *statusfile, pid_t *pid);
+gpg_error_t
+gnupg_spawn_process (const char *pgmname, const char *argv[],
+                     gpg_err_source_t errsource,
+                     void (*preexec)(void), unsigned int flags,
+                     estream_t infp,
+                     estream_t *r_outfp,
+                     estream_t *r_errfp,
+                     pid_t *pid);
 
 
 /* Simplified version of gnupg_spawn_process.  This function forks and
index ae2532d..8e2f941 100644 (file)
@@ -1,5 +1,16 @@
+2010-08-20  Werner Koch  <wk@g10code.com>
+
+       * gpgconf-comp.c (collect_error_output): Remove extra CRs.
+
 2010-08-19  Werner Koch  <wk@g10code.com>
 
+       * gpgconf.c (main): Fix --check-options.
+
+       * gpgconf-comp.c (gc_component_check_options): Replace
+       gnupg_spawn_process_fd by gnupg_spawn_process.
+       (retrieve_options_from_program): Ditto.
+       (collect_error_output): Change to use estream.
+
        * gpgconf-comp.c: Add new backend and component for PINENTRY.
        (gc_component_check_options): Use --version to test the pinentry.
        (gc_component_retrieve_options, gc_component_change_options):
index df7d826..9ee3ce4 100644 (file)
@@ -1363,14 +1363,12 @@ all_digits_p (const char *p, size_t len)
 }
 
 
-/* Collect all error lines from file descriptor FD. Only lines
-   prefixed with TAG are considered.  Close that file descriptor
-   then.  Returns a list of error line items (which may be empty).
-   There is no error return.  */
+/* Collect all error lines from stream FP. Only lines prefixed with
+   TAG are considered.  Returns a list of error line items (which may
+   be empty).  There is no error return.  */
 static error_line_t
-collect_error_output (int fd, const char *tag)
+collect_error_output (estream_t fp, const char *tag)
 {
-  FILE *fp;
   char buffer[1024];
   char *p, *p2, *p3;
   int c, cont_line;
@@ -1378,15 +1376,11 @@ collect_error_output (int fd, const char *tag)
   error_line_t eitem, errlines, *errlines_tail;
   size_t taglen = strlen (tag);
 
-  fp = fdopen (fd, "r");
-  if (!fp)
-    gc_error (1, errno, "can't fdopen pipe for reading");
-
   errlines = NULL;
   errlines_tail = &errlines;
   pos = 0;
   cont_line = 0;
-  while ((c=getc (fp)) != EOF)
+  while ((c=es_getc (fp)) != EOF)
     {
       buffer[pos++] = c;
       if (pos >= sizeof buffer - 5 || c == '\n')
@@ -1401,6 +1395,7 @@ collect_error_output (int fd, const char *tag)
               p = buffer + taglen + 1;
               while (*p == ' ' || *p == '\t')
                 p++;
+              trim_trailing_spaces (p); /* Get rid of extra CRs.  */
               if (!*p)
                 ; /* Empty lines are ignored.  */
               else if ( (p2 = strchr (p, ':')) && (p3 = strchr (p2+1, ':'))
@@ -1445,8 +1440,6 @@ collect_error_output (int fd, const char *tag)
     }
   
   /* We ignore error lines not terminated by a LF.  */
-
-  fclose (fp);
   return errlines;
 }
 
@@ -1466,14 +1459,9 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
   int i;
   pid_t pid;
   int exitcode;
-  int filedes[2];
+  estream_t errfp;
   error_line_t errlines;
 
-  /* We use a temporary file to collect the error output.  It would be
-     better to use a pipe here but as of now we have no suitable
-     fucntion to create a portable pipe outside of exechelp.  Thus it
-     is easier to use the tempfile approach.  */
-
   for (backend = 0; backend < GC_BACKEND_NR; backend++)
     backend_seen[backend] = 0;
 
@@ -1510,23 +1498,15 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
     argv[i++] = "--gpgconf-test";
   argv[i++] = NULL;
   
-  err = gnupg_create_inbound_pipe (filedes);
-  if (err)
-    gc_error (1, 0, _("error creating a pipe: %s\n"), 
-             gpg_strerror (err));
-  
   result = 0;
   errlines = NULL;
-  if (gnupg_spawn_process_fd (pgmname, argv, -1, -1, filedes[1], &pid))
-    {
-      close (filedes[0]);
-      close (filedes[1]);
-      result |= 1; /* Program could not be run.  */
-    }
+  err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT, NULL, 0,
+                             NULL, NULL, &errfp, &pid);
+  if (err)
+    result |= 1; /* Program could not be run.  */
   else 
     {
-      close (filedes[1]);
-      errlines = collect_error_output (filedes[0], 
+      errlines = collect_error_output (errfp, 
                                       gc_component[component].name);
       if (gnupg_wait_process (pgmname, pid, 1, &exitcode))
        {
@@ -1536,6 +1516,7 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
          result |= 2; /* Program returned an error.  */
        }
       gnupg_release_process (pid);
+      es_fclose (errfp);
     }
   
   /* If the program could not be run, we can't tell whether
@@ -1839,41 +1820,32 @@ static void
 retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
 {
   gpg_error_t err;
-  int filedes[2];
   const char *pgmname;
   const char *argv[2];
+  estream_t outfp;
   int exitcode;
   pid_t pid;
   char *line = NULL;
   size_t line_len = 0;
   ssize_t length;
-  FILE *config;
+  estream_t config;
   char *config_filename;
 
-  err = gnupg_create_inbound_pipe (filedes);
-  if (err)
-    gc_error (1, 0, _("error creating a pipe: %s\n"), gpg_strerror (err));
-
   pgmname = (gc_backend[backend].module_name 
              ? gnupg_module_name (gc_backend[backend].module_name) 
              : gc_backend[backend].program );
   argv[0] = "--gpgconf-list";
   argv[1] = NULL;
 
-  err = gnupg_spawn_process_fd (pgmname, argv, -1, filedes[1], -1, &pid);
+  err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT, NULL, 0,
+                             NULL, &outfp, NULL, &pid);
   if (err)
     {
-      close (filedes[0]);
-      close (filedes[1]);
       gc_error (1, 0, "could not gather active options from `%s': %s",
                 pgmname, gpg_strerror (err));
     }
-  close (filedes[1]);
-  config = fdopen (filedes[0], "r");
-  if (!config)
-    gc_error (1, errno, "can't fdopen pipe for reading");
 
-  while ((length = read_line (config, &line, &line_len, NULL)) > 0)
+  while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
     {
       gc_option_t *option;
       char *linep;
@@ -1942,9 +1914,9 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
            option->default_value = xstrdup (default_value);
        }
     }
-  if (length < 0 || ferror (config))
-    gc_error (1, errno, "error reading from %s",pgmname);
-  if (fclose (config) && ferror (config))
+  if (length < 0 || es_ferror (outfp))
+    gc_error (1, errno, "error reading from %s", pgmname);
+  if (es_fclose (outfp) && es_ferror (outfp))
     gc_error (1, errno, "error closing %s", pgmname);
 
   err = gnupg_wait_process (pgmname, pid, 1, &exitcode);
@@ -1957,13 +1929,13 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
   /* At this point, we can parse the configuration file.  */
   config_filename = get_config_filename (component, backend);
 
-  config = fopen (config_filename, "r");
+  config = es_fopen (config_filename, "r");
   if (!config)
     gc_error (0, errno, "warning: can not open config file %s",
              config_filename);
   else
     {
-      while ((length = read_line (config, &line, &line_len, NULL)) > 0)
+      while ((length = es_read_line (config, &line, &line_len, NULL)) > 0)
        {
          char *name;
          char *value;
@@ -2044,9 +2016,9 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
            }
        }
 
-      if (length < 0 || ferror (config))
+      if (length < 0 || es_ferror (config))
        gc_error (1, errno, "error reading from %s", config_filename);
-      if (fclose (config) && ferror (config))
+      if (es_fclose (config) && es_ferror (config))
        gc_error (1, errno, "error closing %s", config_filename);
     }
 
index fc10fbc..222bc48 100644 (file)
@@ -226,15 +226,18 @@ main (int argc, char **argv)
              es_putc ('\n', es_stderr);
              exit (1);
            }
-         gc_component_retrieve_options (idx);
-          if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
-            exit (1);
-         if (cmd == aListOptions)
-           gc_component_list_options (idx, get_outfp (&outfp));
-         else if (cmd == aChangeOptions)
-            gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
-         else
+          if (cmd == aCheckOptions)
            gc_component_check_options (idx, get_outfp (&outfp), NULL);
+          else
+            {
+              gc_component_retrieve_options (idx);
+              if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
+                exit (1);
+              if (cmd == aListOptions)
+                gc_component_list_options (idx, get_outfp (&outfp));
+              else if (cmd == aChangeOptions)
+                gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
+            }
        }
       break;