aboutsummaryrefslogtreecommitdiffstats
path: root/gpgme/posix-io.c
diff options
context:
space:
mode:
Diffstat (limited to 'gpgme/posix-io.c')
-rw-r--r--gpgme/posix-io.c124
1 files changed, 69 insertions, 55 deletions
diff --git a/gpgme/posix-io.c b/gpgme/posix-io.c
index c5f7978e..d0fd5f8e 100644
--- a/gpgme/posix-io.c
+++ b/gpgme/posix-io.c
@@ -146,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,
@@ -155,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)
@@ -179,73 +181,85 @@ _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++)
+ for (i = 0; fd_parent_list[i].fd != -1; i++)
close (fd_parent_list[i].fd);
- return (int) pid;
+ return 0;
}