Fix comment.
[gpgme.git] / gpgme / posix-io.c
index fbfbd22..6b37a44 100644 (file)
@@ -1,23 +1,22 @@
 /* posix-io.c - Posix I/O functions
- *     Copyright (C) 2000 Werner Koch (dd9jn)
- *      Copyright (C) 2001, 2002 g10 Code GmbH
- *
- * This file is part of GPGME.
- *
- * GPGME is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * GPGME is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
+   Copyright (C) 2000 Werner Koch (dd9jn)
+   Copyright (C) 2001, 2002 g10 Code GmbH
+
+   This file is part of GPGME.
+   GPGME is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   GPGME is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with GPGME; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -37,6 +36,8 @@
 #include "util.h"
 #include "io.h"
 #include "sema.h"
+#include "ath.h"
+#include "debug.h"
 
 static struct
 {
@@ -52,7 +53,7 @@ _gpgme_io_read (int fd, void *buffer, size_t count)
   DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
   do
     {
-      nread = read (fd, buffer, count);
+      nread = _gpgme_ath_read (fd, buffer, count);
     }
   while (nread == -1 && errno == EINTR );
   DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
@@ -71,7 +72,7 @@ _gpgme_io_write (int fd, const void *buffer, size_t count)
   _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
   do
     {
-      nwritten = write (fd, buffer, count);
+      nwritten = _gpgme_ath_write (fd, buffer, count);
     }
   while (nwritten == -1 && errno == EINTR);
   DEBUG2 ("fd %d:          wrote %d bytes\n", fd, (int) nwritten);
@@ -145,6 +146,7 @@ _gpgme_io_set_nonblocking (int fd)
 }
 
 
+/* Returns 0 on success, -1 on error.  */
 int
 _gpgme_io_spawn (const char *path, char **argv,
                 struct spawn_fd_item_s *fd_child_list,
@@ -154,6 +156,7 @@ _gpgme_io_spawn (const char *path, char **argv,
   DEFINE_STATIC_LOCK (fixed_signals_lock);
   pid_t pid;
   int i;
+  int status, signo;
 
   LOCK (fixed_signals_lock);
   if (!fixed_signals)
@@ -178,73 +181,86 @@ _gpgme_io_spawn (const char *path, char **argv,
 
   if (!pid)
     {
-      /* Child.  */
-      int duped_stdin = 0;
-      int duped_stderr = 0;
-
-      /* First close all fds which will not be duped.  */
-      for (i=0; fd_child_list[i].fd != -1; i++)
-       if (fd_child_list[i].dup_to == -1)
-         close (fd_child_list[i].fd);
-
-      /* And now dup and close the rest.  */
-      for (i=0; fd_child_list[i].fd != -1; i++)
+      /* Intermediate child to prevent zombie processes.  */
+      if ((pid = fork ()) == 0)
        {
-         if (fd_child_list[i].dup_to != -1)
-           {
-             if (dup2 (fd_child_list[i].fd,
-                        fd_child_list[i].dup_to) == -1)
-               {
-                 DEBUG1 ("dup2 failed in child: %s\n", strerror (errno));
-                 _exit (8);
-                }
-             if (fd_child_list[i].dup_to == 0)
-               duped_stdin=1;
-             if (fd_child_list[i].dup_to == 2)
-               duped_stderr=1;
+         /* Child.  */
+         int duped_stdin = 0;
+         int duped_stderr = 0;
+
+         /* First close all fds which will not be duped.  */
+         for (i=0; fd_child_list[i].fd != -1; i++)
+           if (fd_child_list[i].dup_to == -1)
              close (fd_child_list[i].fd);
-            }
-        }
 
-      if (!duped_stdin || !duped_stderr)
-       {
-         int fd = open ("/dev/null", O_RDWR);
-         if (fd == -1)
+         /* And now dup and close the rest.  */
+         for (i=0; fd_child_list[i].fd != -1; i++)
            {
-             DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno));
-             _exit (8);
-            }
-         /* Make sure that the process has a connected stdin.  */
-         if (!duped_stdin)
+             if (fd_child_list[i].dup_to != -1)
+               {
+                 if (dup2 (fd_child_list[i].fd,
+                           fd_child_list[i].dup_to) == -1)
+                   {
+                     DEBUG1 ("dup2 failed in child: %s\n", strerror (errno));
+                     _exit (8);
+                   }
+                 if (fd_child_list[i].dup_to == 0)
+                   duped_stdin=1;
+                 if (fd_child_list[i].dup_to == 2)
+                   duped_stderr=1;
+                 close (fd_child_list[i].fd);
+               }
+           }
+         
+         if (!duped_stdin || !duped_stderr)
            {
-             if (dup2 (fd, 0) == -1)
+             int fd = open ("/dev/null", O_RDWR);
+             if (fd == -1)
                {
-                 DEBUG1("dup2(/dev/null, 0) failed: %s\n",
-                        strerror (errno));
+                 DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno));
                  _exit (8);
-                }
-            }
-         if (!duped_stderr)
-           if (dup2 (fd, 2) == -1)
-             {
-               DEBUG1 ("dup2(dev/null, 2) failed: %s\n", strerror (errno));
-               _exit (8);
-             }
-         close (fd);
-       }
+               }
+             /* Make sure that the process has a connected stdin.  */
+             if (!duped_stdin)
+               {
+                 if (dup2 (fd, 0) == -1)
+                   {
+                     DEBUG1("dup2(/dev/null, 0) failed: %s\n",
+                            strerror (errno));
+                     _exit (8);
+                   }
+               }
+             if (!duped_stderr)
+               if (dup2 (fd, 2) == -1)
+                 {
+                   DEBUG1 ("dup2(dev/null, 2) failed: %s\n",
+                           strerror (errno));
+                   _exit (8);
+                 }
+             close (fd);
+           }
     
-      execv ( path, argv );
-      /* Hmm: in that case we could write a special status code to the
-        status-pipe.  */
-      DEBUG1 ("exec of `%s' failed\n", path);
-      _exit (8);
-    } /* End child.  */
+         execv ( path, argv );
+         /* Hmm: in that case we could write a special status code to the
+            status-pipe.  */
+         DEBUG1 ("exec of `%s' failed\n", path);
+         _exit (8);
+       } /* End child.  */
+      if (pid == -1)
+       _exit (1);
+      else
+       _exit (0);
+    }
     
+  _gpgme_io_waitpid (pid, 1, &status, &signo);
+  if (status)
+    return -1;
+
   /* .dup_to is not used in the parent list.  */
-  for (i=0; fd_parent_list[i].fd != -1; i++)
-    close (fd_parent_list[i].fd);
+  for (i = 0; fd_parent_list[i].fd != -1; i++)
+    _gpgme_io_close (fd_parent_list[i].fd);
 
-  return (int) pid;
+  return 0;
 }
 
 
@@ -255,7 +271,7 @@ _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
 
   *r_status = 0;
   *r_signal = 0;
-  if (waitpid (pid, &status, hang? 0 : WNOHANG) == pid)
+  if (_gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG) == pid)
     {
       if (WIFSIGNALED (status))
        {
@@ -286,7 +302,7 @@ _gpgme_io_kill (int pid, int hard)
  *          >0 = number of signaled fds
  */
 int
-_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds)
+_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
 {
   fd_set readfds;
   fd_set writefds;
@@ -297,6 +313,8 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds)
   FD_ZERO (&readfds);
   FD_ZERO (&writefds);
   max_fd = 0;
+  if (nonblock)
+    timeout.tv_sec = 0;
 
   DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ ");
   any = 0;
@@ -332,7 +350,8 @@ _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds)
 
   do
     {
-      count = select (max_fd + 1, &readfds, &writefds, NULL, &timeout);
+      count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
+                                &timeout);
     }
   while (count < 0 && errno == EINTR);
   if (count < 0)