* assuan-connect.c (assuan_pipe_connect): New function.
[gnupg.git] / assuan / assuan-connect.c
index d1c87fc..294a26c 100644 (file)
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 
 #include "assuan-defs.h"
 
+/* 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.  If NAME is NULL, the first element in ARGV is
+   used.  */
+AssuanError
+assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
+{
+  static int fixed_signals = 0;
+  AssuanError err;
+  int rp[2];
+  int wp[2];
+  int fd[2];
+
+  if (!argv || !argv[0])
+    return ASSUAN_General_Error;
+
+  if (!name)
+    name = argv[0];
+
+  if (!fixed_signals)
+    { 
+      struct sigaction act;
+        
+      sigaction (SIGPIPE, NULL, &act);
+      if (act.sa_handler == SIG_DFL)
+       {
+         act.sa_handler = SIG_IGN;
+         sigemptyset (&act.sa_mask);
+         act.sa_flags = 0;
+         sigaction (SIGPIPE, &act, NULL);
+        }
+      fixed_signals = 1;
+      /* FIXME: This is not MT safe */
+    }
+
+  if (pipe (rp) < 0)
+    return ASSUAN_General_Error;
+
+  if (pipe (wp) < 0)
+    {
+      close (rp[0]);
+      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.  */
+
+  err = assuan_init_pipe_server (ctx, fd);  /* FIXME: Common code should be factored out.  */
+  if (err)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      close (wp[0]);
+      close (wp[1]);
+      return err;
+    }
+
+  (*ctx)->pid = fork ();
+  if ((*ctx)->pid < 0)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      close (wp[0]);
+      close (wp[1]);
+      assuan_deinit_pipe_server (*ctx);  /* FIXME: Common code should be factored out.  */
+      return ASSUAN_General_Error;
+    }
+
+  if ((*ctx)->pid == 0)
+    {
+      close (rp[0]);
+      close (wp[1]);
+      if (rp[1] != STDOUT_FILENO)
+       {
+         dup2 (rp[1], STDOUT_FILENO);  /* Child's outbound is write end of read pipe.  */
+         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);
+    }
+
+  close (rp[1]);
+  close (wp[0]);
+  _assuan_read_line (*ctx); /* FIXME: Handshake.  */
+  return 0;
+}
+
+void
+assuan_pipe_disconnect (ASSUAN_CONTEXT ctx)
+{
+  _assuan_write_line (ctx, "BYE");
+  close (ctx->inbound.fd);
+  close (ctx->outbound.fd);
+  waitpid (ctx->pid, NULL, 0);  /* FIXME Check return value.  */
+  assuan_deinit_pipe_server (ctx);
+}