aboutsummaryrefslogtreecommitdiffstats
path: root/assuan/assuan-pipe-connect.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--assuan/assuan-pipe-connect.c702
1 files changed, 486 insertions, 216 deletions
diff --git a/assuan/assuan-pipe-connect.c b/assuan/assuan-pipe-connect.c
index ecedb166..8ee9c748 100644
--- a/assuan/assuan-pipe-connect.c
+++ b/assuan/assuan-pipe-connect.c
@@ -1,5 +1,5 @@
/* assuan-pipe-connect.c - Establish a pipe connection (client)
- * Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
@@ -15,7 +15,8 @@
*
* You should have received a copy of the GNU Lesser 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
*/
#ifdef HAVE_CONFIG_H
@@ -38,6 +39,19 @@
#include "assuan-defs.h"
+/* Hacks for Slowaris. */
+#ifndef PF_LOCAL
+# ifdef PF_UNIX
+# define PF_LOCAL PF_UNIX
+# else
+# define PF_LOCAL AF_UNIX
+# endif
+#endif
+#ifndef AF_LOCAL
+# define AF_LOCAL AF_UNIX
+#endif
+
+
#ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
#else
@@ -111,6 +125,8 @@ do_finish (assuan_context_t ctx)
if (ctx->inbound.fd != -1)
{
_assuan_close (ctx->inbound.fd);
+ if (ctx->inbound.fd == ctx->outbound.fd)
+ ctx->outbound.fd = -1;
ctx->inbound.fd = -1;
}
if (ctx->outbound.fd != -1)
@@ -123,7 +139,7 @@ do_finish (assuan_context_t ctx)
#ifndef HAVE_W32_SYSTEM
#ifndef _ASSUAN_USE_DOUBLE_FORK
if (!ctx->flags.no_waitpid)
- waitpid (ctx->pid, NULL, 0);
+ _assuan_waitpid (ctx->pid, NULL, 0);
ctx->pid = -1;
#endif
#endif /*!HAVE_W32_SYSTEM*/
@@ -138,6 +154,402 @@ do_deinit (assuan_context_t ctx)
}
+/* Helper for pipe_connect. */
+static assuan_error_t
+initial_handshake (assuan_context_t *ctx)
+{
+ int okay, off;
+ assuan_error_t err;
+
+ err = _assuan_read_from_server (*ctx, &okay, &off);
+ if (err)
+ _assuan_log_printf ("can't connect server: %s\n",
+ assuan_strerror (err));
+ else if (okay != 1)
+ {
+ _assuan_log_printf ("can't connect server: `%s'\n",
+ (*ctx)->inbound.line);
+ err = _assuan_error (ASSUAN_Connect_Failed);
+ }
+
+ if (err)
+ {
+ assuan_disconnect (*ctx);
+ *ctx = NULL;
+ }
+ return err;
+}
+
+
+#ifndef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_unix
+/* Unix version of the pipe connection code. We use an extra macro to
+ make ChangeLog entries easier. */
+static assuan_error_t
+pipe_connect_unix (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ assuan_error_t err;
+ int rp[2];
+ int wp[2];
+ char mypidstr[50];
+
+ if (!ctx || !name || !argv || !argv[0])
+ return _assuan_error (ASSUAN_Invalid_Value);
+
+ fix_signals ();
+
+ sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+ if (pipe (rp) < 0)
+ return _assuan_error (ASSUAN_General_Error);
+
+ if (pipe (wp) < 0)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ err = _assuan_new_context (ctx);
+ if (err)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ close (wp[0]);
+ close (wp[1]);
+ return err;
+ }
+ (*ctx)->pipe_mode = 1;
+ (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
+ (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
+ (*ctx)->deinit_handler = do_deinit;
+ (*ctx)->finish_handler = do_finish;
+
+ /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID
+ stored here is actually soon useless. */
+ (*ctx)->pid = fork ();
+ if ((*ctx)->pid < 0)
+ {
+ close (rp[0]);
+ close (rp[1]);
+ close (wp[0]);
+ close (wp[1]);
+ _assuan_release_context (*ctx);
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ if ((*ctx)->pid == 0)
+ {
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ pid_t pid;
+
+ if ((pid = fork ()) == 0)
+#endif
+ {
+ int i, n;
+ char errbuf[512];
+ int *fdp;
+
+ if (atfork)
+ atfork (atforkvalue, 0);
+
+ /* Dup handles to stdin/stdout. */
+ if (rp[1] != STDOUT_FILENO)
+ {
+ if (dup2 (rp[1], STDOUT_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2 failed in child: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+ if (wp[0] != STDIN_FILENO)
+ {
+ if (dup2 (wp[0], STDIN_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2 failed in child: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ int fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1)
+ {
+ _assuan_log_printf ("can't open `/dev/null': %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ if (dup2 (fd, STDERR_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+
+ /* Close all files which will not be duped and are not in the
+ fd_child_list. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=0; i < n; i++)
+ {
+ if ( i == STDIN_FILENO || i == STDOUT_FILENO
+ || i == STDERR_FILENO)
+ continue;
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ while (*fdp != -1 && *fdp != i)
+ fdp++;
+ }
+
+ if (!(fdp && *fdp != -1))
+ close(i);
+ }
+ errno = 0;
+
+ /* We store our parents pid in the environment so that the
+ execed assuan server is able to read the actual pid of the
+ client. The server can't use getppid because it might have
+ been double forked before the assuan server has been
+ initialized. */
+ setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+ /* Make sure that we never pass a connection fd variable
+ when using a simple pipe. */
+ unsetenv ("_assuan_connection_fd");
+
+ execv (name, (char *const *) argv);
+ /* oops - use the pipe to tell the parent about it */
+ snprintf (errbuf, sizeof(errbuf)-1,
+ "ERR %d can't exec `%s': %.50s\n",
+ _assuan_error (ASSUAN_Problem_Starting_Server),
+ name, strerror (errno));
+ errbuf[sizeof(errbuf)-1] = 0;
+ writen (1, errbuf, strlen (errbuf));
+ _exit (4);
+ }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ if (pid == -1)
+ _exit (1);
+ else
+ _exit (0);
+#endif
+ }
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ _assuan_waitpid ((*ctx)->pid, NULL, 0);
+ (*ctx)->pid = -1;
+#endif
+
+ close (rp[1]);
+ close (wp[0]);
+
+ return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+#ifndef HAVE_W32_SYSTEM
+/* This function is similar to pipe_connect but uses a socketpair and
+ sets the I/O up to use sendmsg/recvmsg. */
+static assuan_error_t
+socketpair_connect (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ assuan_error_t err;
+ int fds[2];
+ char mypidstr[50];
+
+ if (!ctx
+ || (name && (!argv || !argv[0]))
+ || (!name && argv))
+ return _assuan_error (ASSUAN_Invalid_Value);
+
+ fix_signals ();
+
+ sprintf (mypidstr, "%lu", (unsigned long)getpid ());
+
+ if ( socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) )
+ {
+ _assuan_log_printf ("socketpair failed: %s\n", strerror (errno));
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ err = _assuan_new_context (ctx);
+ if (err)
+ {
+ close (fds[0]);
+ close (fds[1]);
+ return err;
+ }
+ (*ctx)->pipe_mode = 1;
+ (*ctx)->inbound.fd = fds[0];
+ (*ctx)->outbound.fd = fds[0];
+ _assuan_init_uds_io (*ctx);
+ (*ctx)->deinit_handler = _assuan_uds_deinit;
+ (*ctx)->finish_handler = do_finish;
+
+ (*ctx)->pid = fork ();
+ if ((*ctx)->pid < 0)
+ {
+ close (fds[0]);
+ close (fds[1]);
+ _assuan_release_context (*ctx);
+ *ctx = NULL;
+ return _assuan_error (ASSUAN_General_Error);
+ }
+
+ if ((*ctx)->pid == 0)
+ {
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ pid_t pid;
+
+ if ((pid = fork ()) == 0)
+#endif
+ {
+ int fd, i, n;
+ char errbuf[512];
+ int *fdp;
+
+ if (atfork)
+ atfork (atforkvalue, 0);
+
+ /* Connect stdin and stdout to /dev/null. */
+ fd = open ("/dev/null", O_RDONLY);
+ if (fd == -1 || dup2 (fd, STDIN_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1 || dup2 (fd, STDOUT_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+
+ /* Dup stderr to /dev/null unless it is in the list of FDs to be
+ passed to the child. */
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
+ ;
+ }
+ if (!fdp || *fdp == -1)
+ {
+ fd = open ("/dev/null", O_WRONLY);
+ if (fd == -1 || dup2 (fd, STDERR_FILENO) == -1)
+ {
+ _assuan_log_printf ("dup2(dev/null) failed: %s\n",
+ strerror (errno));
+ _exit (4);
+ }
+ }
+
+
+ /* Close all files which will not be duped, are not in the
+ fd_child_list and are not the connection fd. */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=0; i < n; i++)
+ {
+ if ( i == STDIN_FILENO || i == STDOUT_FILENO
+ || i == STDERR_FILENO || i == fds[1])
+ continue;
+ fdp = fd_child_list;
+ if (fdp)
+ {
+ while (*fdp != -1 && *fdp != i)
+ fdp++;
+ }
+
+ if (!(fdp && *fdp != -1))
+ close(i);
+ }
+ errno = 0;
+
+ /* We store our parents pid in the environment so that the
+ execed assuan server is able to read the actual pid of the
+ client. The server can't use getppid becuase it might have
+ been double forked before the assuan server has been
+ initialized. */
+ setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
+
+ /* Now set the environment variable used to convey the
+ connection's file descriptor. */
+ sprintf (mypidstr, "%d", fds[1]);
+ if (setenv ("_assuan_connection_fd", mypidstr, 1))
+ {
+ _assuan_log_printf ("setenv failed: %s\n", strerror (errno));
+ _exit (4);
+ }
+
+ if (!name && !argv)
+ {
+ /* No name and no args given, thus we don't do an exec
+ but continue the forked process. */
+ _assuan_release_context (*ctx);
+ *ctx = NULL;
+ return 0;
+ }
+
+ execv (name, (char *const *) argv);
+ /* oops - use the pipe to tell the parent about it */
+ snprintf (errbuf, sizeof(errbuf)-1,
+ "ERR %d can't exec `%s': %.50s\n",
+ _assuan_error (ASSUAN_Problem_Starting_Server),
+ name, strerror (errno));
+ errbuf[sizeof(errbuf)-1] = 0;
+ writen (fds[1], errbuf, strlen (errbuf));
+ _exit (4);
+ }
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ if (pid == -1)
+ _exit (1);
+ else
+ _exit (0);
+#endif
+ }
+
+
+#ifdef _ASSUAN_USE_DOUBLE_FORK
+ _assuan_waitpid ((*ctx)->pid, NULL, 0);
+ (*ctx)->pid = -1;
+#endif
+
+ close (fds[1]);
+
+ return initial_handshake (ctx);
+}
+#endif /*!HAVE_W32_SYSTEM*/
+
+
+
#ifdef HAVE_W32_SYSTEM
/* Build a command line for use with W32's CreateProcess. On success
CMDLINE gets the address of a newly allocated string. */
@@ -236,21 +648,16 @@ create_inheritable_pipe (int filedes[2], int for_write)
#endif /*HAVE_W32_SYSTEM*/
-/* Connect to a server over a pipe, creating the assuan context and
- returning it in CTX. The server filename is NAME, the argument
- vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
- descriptors not to close in the child. ATFORK is called in the
- child right after the fork; ATFORKVALUE is passed as the first
- argument and 0 is passed as the second argument. The ATFORK
- function should only act if the second value is 0. */
-assuan_error_t
-assuan_pipe_connect2 (assuan_context_t *ctx,
- const char *name, const char *const argv[],
- int *fd_child_list,
- void (*atfork) (void *opaque, int reserved),
- void *atforkvalue)
-{
#ifdef HAVE_W32_SYSTEM
+#define pipe_connect pipe_connect_w32
+/* W32 version of the pipe connection code. */
+static assuan_error_t
+pipe_connect_w32 (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
assuan_error_t err;
int rp[2];
int wp[2];
@@ -269,7 +676,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
HANDLE nullfd = INVALID_HANDLE_VALUE;
if (!ctx || !name || !argv || !argv[0])
- return ASSUAN_Invalid_Value;
+ return _assuan_error (ASSUAN_Invalid_Value);
fix_signals ();
@@ -277,13 +684,13 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
/* Build the command line. */
if (build_w32_commandline (argv, &cmdline))
- return ASSUAN_Out_Of_Core;
+ return _assuan_error (ASSUAN_Out_Of_Core);
/* Create thew two pipes. */
if (create_inheritable_pipe (rp, 0))
{
xfree (cmdline);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
if (create_inheritable_pipe (wp, 1))
@@ -291,7 +698,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
CloseHandle (fd_to_handle (rp[0]));
CloseHandle (fd_to_handle (rp[1]));
xfree (cmdline);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
@@ -303,7 +710,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
CloseHandle (fd_to_handle (wp[0]));
CloseHandle (fd_to_handle (wp[1]));
xfree (cmdline);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
(*ctx)->pipe_mode = 1;
@@ -390,7 +797,7 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
CloseHandle (nullfd);
xfree (cmdline);
_assuan_release_context (*ctx);
- return ASSUAN_General_Error;
+ return _assuan_error (ASSUAN_General_Error);
}
xfree (cmdline);
cmdline = NULL;
@@ -413,200 +820,11 @@ assuan_pipe_connect2 (assuan_context_t *ctx,
(*ctx)->pid = 0; /* We don't use the PID. */
CloseHandle (pi.hProcess); /* We don't need to wait for the process. */
-#else /*!HAVE_W32_SYSTEM*/
- assuan_error_t err;
- int rp[2];
- int wp[2];
- char mypidstr[50];
-
- if (!ctx || !name || !argv || !argv[0])
- return ASSUAN_Invalid_Value;
-
- fix_signals ();
-
- sprintf (mypidstr, "%lu", (unsigned long)getpid ());
-
- if (pipe (rp) < 0)
- return ASSUAN_General_Error;
-
- if (pipe (wp) < 0)
- {
- close (rp[0]);
- close (rp[1]);
- return ASSUAN_General_Error;
- }
-
- err = _assuan_new_context (ctx);
- if (err)
- {
- close (rp[0]);
- close (rp[1]);
- close (wp[0]);
- close (wp[1]);
- return err;
- }
- (*ctx)->pipe_mode = 1;
- (*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
- (*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
- (*ctx)->deinit_handler = do_deinit;
- (*ctx)->finish_handler = do_finish;
-
- /* FIXME: For GPGME we should better use _gpgme_io_spawn. The PID
- stored here is actually soon useless. */
- (*ctx)->pid = fork ();
- if ((*ctx)->pid < 0)
- {
- close (rp[0]);
- close (rp[1]);
- close (wp[0]);
- close (wp[1]);
- _assuan_release_context (*ctx);
- return ASSUAN_General_Error;
- }
-
- if ((*ctx)->pid == 0)
- {
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- pid_t pid;
-
- if ((pid = fork ()) == 0)
-#endif
- {
- int i, n;
- char errbuf[512];
- int *fdp;
-
- if (atfork)
- atfork (atforkvalue, 0);
-
- /* Dup handles to stdin/stdout. */
- if (rp[1] != STDOUT_FILENO)
- {
- if (dup2 (rp[1], STDOUT_FILENO) == -1)
- {
- _assuan_log_printf ("dup2 failed in child: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
- if (wp[0] != STDIN_FILENO)
- {
- if (dup2 (wp[0], STDIN_FILENO) == -1)
- {
- _assuan_log_printf ("dup2 failed in child: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
-
- /* Dup stderr to /dev/null unless it is in the list of FDs to be
- passed to the child. */
- fdp = fd_child_list;
- if (fdp)
- {
- for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
- ;
- }
- if (!fdp || *fdp == -1)
- {
- int fd = open ("/dev/null", O_WRONLY);
- if (fd == -1)
- {
- _assuan_log_printf ("can't open `/dev/null': %s\n",
- strerror (errno));
- _exit (4);
- }
- if (dup2 (fd, STDERR_FILENO) == -1)
- {
- _assuan_log_printf ("dup2(dev/null, 2) failed: %s\n",
- strerror (errno));
- _exit (4);
- }
- }
-
-
- /* Close all files which will not be duped and are not in the
- fd_child_list. */
- n = sysconf (_SC_OPEN_MAX);
- if (n < 0)
- n = MAX_OPEN_FDS;
- for (i=0; i < n; i++)
- {
- if ( i == STDIN_FILENO || i == STDOUT_FILENO
- || i == STDERR_FILENO)
- continue;
- fdp = fd_child_list;
- if (fdp)
- {
- while (*fdp != -1 && *fdp != i)
- fdp++;
- }
-
- if (!(fdp && *fdp != -1))
- close(i);
- }
- errno = 0;
-
- /* We store our parents pid in the environment so that the
- execed assuan server is able to read the actual pid of the
- client. The server can't use getppid becuase it might have
- been double forked before the assuan server has been
- initialized. */
- setenv ("_assuan_pipe_connect_pid", mypidstr, 1);
-
- execv (name, (char *const *) argv);
- /* oops - use the pipe to tell the parent about it */
- snprintf (errbuf, sizeof(errbuf)-1,
- "ERR %d can't exec `%s': %.50s\n",
- ASSUAN_Problem_Starting_Server, name, strerror (errno));
- errbuf[sizeof(errbuf)-1] = 0;
- writen (1, errbuf, strlen (errbuf));
- _exit (4);
- }
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- if (pid == -1)
- _exit (1);
- else
- _exit (0);
-#endif
- }
-
-#ifdef _ASSUAN_USE_DOUBLE_FORK
- waitpid ((*ctx)->pid, NULL, 0);
- (*ctx)->pid = -1;
-#endif
-
- close (rp[1]);
- close (wp[0]);
-
-#endif /*!HAVE_W32_SYSTEM*/
-
- /* initial handshake */
- {
- int okay, off;
-
- err = _assuan_read_from_server (*ctx, &okay, &off);
- if (err)
- _assuan_log_printf ("can't connect server: %s\n",
- assuan_strerror (err));
- else if (okay != 1)
- {
- _assuan_log_printf ("can't connect server: `%s'\n",
- (*ctx)->inbound.line);
- err = ASSUAN_Connect_Failed;
- }
- }
-
- if (err)
- {
- assuan_disconnect (*ctx);
- *ctx = NULL;
- }
-
- return err;
+ return initial_handshake (ctx);
}
+#endif /*HAVE_W32_SYSTEM*/
-
+
/* Connect to a server over a pipe, creating the assuan context and
returning it in CTX. The server filename is NAME, the argument
vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
@@ -615,5 +833,57 @@ assuan_error_t
assuan_pipe_connect (assuan_context_t *ctx, const char *name,
const char *const argv[], int *fd_child_list)
{
- return assuan_pipe_connect2 (ctx, name, argv, fd_child_list, NULL, NULL);
+ return pipe_connect (ctx, name, argv, fd_child_list, NULL, NULL);
+}
+
+
+
+assuan_error_t
+assuan_pipe_connect2 (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue)
+{
+ return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
+}
+
+
+/* Connect to a server over a full-duplex socket (i.e. created by
+ socketpair), creating the assuan context and returning it in CTX.
+ The server filename is NAME, the argument vector in ARGV.
+ FD_CHILD_LIST is a -1 terminated list of file descriptors not to
+ close in the child. ATFORK is called in the child right after the
+ fork; ATFORKVALUE is passed as the first argument and 0 is passed
+ as the second argument. The ATFORK function should only act if the
+ second value is 0.
+
+ For now FLAGS may either take the value 0 to behave like
+ assuan_pipe_connect2 or 1 to enable the described full-duplex
+ socket behaviour.
+
+ If NAME as well as ARGV are NULL, no exec is done but the same
+ process is continued. However all file descriptors are closed and
+ some special environment variables are set. To let the caller
+ detect whether the child or the parent continues, the child returns
+ a CTX of NULL. */
+assuan_error_t
+assuan_pipe_connect_ext (assuan_context_t *ctx,
+ const char *name, const char *const argv[],
+ int *fd_child_list,
+ void (*atfork) (void *opaque, int reserved),
+ void *atforkvalue, unsigned int flags)
+{
+ if ((flags & 1))
+ {
+#ifdef HAVE_W32_SYSTEM
+ return _assuan_error (ASSUAN_Not_Implemented);
+#else
+ return socketpair_connect (ctx, name, argv, fd_child_list,
+ atfork, atforkvalue);
+#endif
+ }
+ else
+ return pipe_connect (ctx, name, argv, fd_child_list, atfork, atforkvalue);
}
+