* assuan-connect.c (assuan_pipe_connect): New function.
[gnupg.git] / assuan / assuan-connect.c
1 /* assuan-connect.c - Establish a connection (client) 
2  *      Copyright (C) 2001 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <signal.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29
30 #include "assuan-defs.h"
31
32 /* Connect to a server over a pipe, creating the assuan context and
33    returning it in CTX.  The server filename is NAME, the argument
34    vector in ARGV.  If NAME is NULL, the first element in ARGV is
35    used.  */
36 AssuanError
37 assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[])
38 {
39   static int fixed_signals = 0;
40   AssuanError err;
41   int rp[2];
42   int wp[2];
43   int fd[2];
44
45   if (!argv || !argv[0])
46     return ASSUAN_General_Error;
47
48   if (!name)
49     name = argv[0];
50
51   if (!fixed_signals)
52     { 
53       struct sigaction act;
54         
55       sigaction (SIGPIPE, NULL, &act);
56       if (act.sa_handler == SIG_DFL)
57         {
58           act.sa_handler = SIG_IGN;
59           sigemptyset (&act.sa_mask);
60           act.sa_flags = 0;
61           sigaction (SIGPIPE, &act, NULL);
62         }
63       fixed_signals = 1;
64       /* FIXME: This is not MT safe */
65     }
66
67   if (pipe (rp) < 0)
68     return ASSUAN_General_Error;
69
70   if (pipe (wp) < 0)
71     {
72       close (rp[0]);
73       close (rp[1]);
74       return ASSUAN_General_Error;
75     }
76
77   fd[0] = rp[0];  /* Our inbound is read end of read pipe.  */
78   fd[1] = wp[1];  /* Our outbound is write end of write pipe.  */
79
80   err = assuan_init_pipe_server (ctx, fd);  /* FIXME: Common code should be factored out.  */
81   if (err)
82     {
83       close (rp[0]);
84       close (rp[1]);
85       close (wp[0]);
86       close (wp[1]);
87       return err;
88     }
89
90   (*ctx)->pid = fork ();
91   if ((*ctx)->pid < 0)
92     {
93       close (rp[0]);
94       close (rp[1]);
95       close (wp[0]);
96       close (wp[1]);
97       assuan_deinit_pipe_server (*ctx);  /* FIXME: Common code should be factored out.  */
98       return ASSUAN_General_Error;
99     }
100
101   if ((*ctx)->pid == 0)
102     {
103       close (rp[0]);
104       close (wp[1]);
105       if (rp[1] != STDOUT_FILENO)
106         {
107           dup2 (rp[1], STDOUT_FILENO);  /* Child's outbound is write end of read pipe.  */
108           close (rp[1]);
109         }
110       if (wp[0] != STDIN_FILENO)
111         {
112           dup2 (wp[0], STDIN_FILENO);  /* Child's inbound is read end of write pipe.  */
113           close (wp[0]);
114         }
115       execv (name, argv);
116       _exit (1);
117     }
118
119   close (rp[1]);
120   close (wp[0]);
121   _assuan_read_line (*ctx); /* FIXME: Handshake.  */
122   return 0;
123 }
124
125 void
126 assuan_pipe_disconnect (ASSUAN_CONTEXT ctx)
127 {
128   _assuan_write_line (ctx, "BYE");
129   close (ctx->inbound.fd);
130   close (ctx->outbound.fd);
131   waitpid (ctx->pid, NULL, 0);  /* FIXME Check return value.  */
132   assuan_deinit_pipe_server (ctx);
133 }