aboutsummaryrefslogtreecommitdiffstats
path: root/assuan/assuan-connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'assuan/assuan-connect.c')
-rw-r--r--assuan/assuan-connect.c136
1 files changed, 118 insertions, 18 deletions
diff --git a/assuan/assuan-connect.c b/assuan/assuan-connect.c
index 37d42625..683c7f06 100644
--- a/assuan/assuan-connect.c
+++ b/assuan/assuan-connect.c
@@ -18,17 +18,57 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif
+
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
+#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "assuan-defs.h"
+#ifdef _POSIX_OPEN_MAX
+#define MAX_OPEN_FDS _POSIX_OPEN_MAX
+#else
+#define MAX_OPEN_FDS 20
+#endif
+
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#define LOGERROR1(a,b) log_error ((a), (b))
+#else
+#define LOGERROR1(a,b) fprintf (stderr, (a), (b))
+#endif
+
+
+
+static int
+writen ( int fd, const char *buffer, size_t length )
+{
+ while (length)
+ {
+ int nwritten = write (fd, buffer, length);
+
+ if (nwritten < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ return -1; /* write error */
+ }
+ length -= nwritten;
+ buffer += nwritten;
+ }
+ return 0; /* okay */
+}
+
+
+
/* 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. */
@@ -41,8 +81,8 @@ assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
int wp[2];
int fd[2];
- if (!name || !argv || !argv[0])
- return ASSUAN_General_Error;
+ if (!ctx || !name || !argv || !argv[0])
+ return ASSUAN_Invalid_Value;
if (!fixed_signals)
{
@@ -69,7 +109,7 @@ assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
close (rp[1]);
return ASSUAN_General_Error;
}
-
+
fd[0] = rp[0]; /* Our inbound is read end of read pipe. */
fd[1] = wp[1]; /* Our outbound is write end of write pipe. */
@@ -82,6 +122,7 @@ assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
close (wp[1]);
return err;
}
+ (*ctx)->is_server = 0;
(*ctx)->pid = fork ();
if ((*ctx)->pid < 0)
@@ -96,32 +137,89 @@ assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
if ((*ctx)->pid == 0)
{
- close (rp[0]);
- close (wp[1]);
+ int i, n;
+ char errbuf[512];
+#ifdef HAVE_JNLIB_LOGGING
+ int log_fd = log_get_fd ();
+#endif
+ /* close all files which will not be duped but keep stderr
+ and log_stream for now */
+ n = sysconf (_SC_OPEN_MAX);
+ if (n < 0)
+ n = MAX_OPEN_FDS;
+ for (i=0; i < n; i++)
+ {
+ if (i != fileno (stderr)
+#ifdef HAVE_JNLIB_LOGGING
+ && i != log_fd
+#endif
+ && i != rp[1] && i != wp[0])
+ close(i);
+ }
+ errno = 0;
+
+ /* Dup handles and to stdin/stdout and exec */
if (rp[1] != STDOUT_FILENO)
- {
- dup2 (rp[1], STDOUT_FILENO); /* Child's outbound is write end of read pipe. */
- close (rp[1]);
- }
+ {
+ if (dup2 (rp[1], STDOUT_FILENO) == -1)
+ {
+ LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
+ _exit (4);
+ }
+ close (rp[1]);
+ }
if (wp[0] != STDIN_FILENO)
- {
- dup2 (wp[0], STDIN_FILENO); /* Child's inbound is read end of write pipe. */
- close (wp[0]);
- }
- execv (name, argv);
- _exit (1);
+ {
+ if (dup2 (wp[0], STDIN_FILENO) == -1)
+ {
+ LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
+ _exit (4);
+ }
+ close (wp[0]);
+ }
+
+ execv (name, 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);
}
close (rp[1]);
close (wp[0]);
- _assuan_read_line (*ctx); /* FIXME: Handshake. */
- return 0;
+
+ /* initial handshake */
+ {
+ int okay, off;
+
+ err = _assuan_read_from_server (*ctx, &okay, &off);
+ if (err)
+ {
+ LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
+ }
+ else if (okay != 1)
+ {
+ LOGERROR1 ("can't connect server: `%s'\n", (*ctx)->inbound.line);
+ err = ASSUAN_Connect_Failed;
+ }
+ }
+
+ if (err)
+ {
+ if ((*ctx)->pid != -1)
+ waitpid ((*ctx)->pid, NULL, 0); /* FIXME Check return value. */
+ assuan_deinit_pipe_server (*ctx); /* FIXME: Common code should be factored out. */
+ }
+
+ return err;
}
void
assuan_pipe_disconnect (ASSUAN_CONTEXT ctx)
{
- _assuan_write_line (ctx, "BYE");
+ assuan_write_line (ctx, "BYE");
close (ctx->inbound.fd);
close (ctx->outbound.fd);
waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */
@@ -133,3 +231,5 @@ assuan_get_pid (ASSUAN_CONTEXT ctx)
{
return ctx ? ctx->pid : -1;
}
+
+