1 /*
2 ** Copyright 2001-2006 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 static const char rcsid[]="$Id: fork.c,v 1.3 2006/05/28 15:29:52 mrsam Exp $";
7
8 #include "config.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <signal.h>
14 #include <errno.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <sys/time.h>
18 #if HAVE_SYS_WAIT_H
19 #include <sys/wait.h>
20 #endif
21 #ifndef WEXITSTATUS
22 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
23 #endif
24 #ifndef WIFEXITED
25 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
26 #endif
27
28 #include "gpg.h"
29 #include "gpglib.h"
30
31 extern int libmail_gpg_stdin, libmail_gpg_stdout, libmail_gpg_stderr;
32 extern pid_t libmail_gpg_pid;
33
34
35 /*
36 ** Helper function: for and run pgp, with the given file descriptors and
37 ** options.
38 */
39
libmail_gpg_fork(int * libmail_gpg_stdin,int * libmail_gpg_stdout,int * libmail_gpg_stderr,const char * gpgdir,char ** argvec)40 pid_t libmail_gpg_fork(int *libmail_gpg_stdin, int *libmail_gpg_stdout,
41 int *libmail_gpg_stderr,
42 const char *gpgdir,
43 char **argvec)
44 {
45 int pipein[2], pipeout[2], pipeerr[2];
46 pid_t p;
47 char *s;
48
49 if (libmail_gpg_stdin && pipe(pipein) < 0)
50 return (-1);
51
52 if (libmail_gpg_stdout && pipe(pipeout) < 0)
53 {
54 if (libmail_gpg_stdin)
55 {
56 close(pipein[0]);
57 close(pipein[1]);
58 }
59 return (-1);
60 }
61
62 if (libmail_gpg_stderr && pipe(pipeerr) < 0)
63 {
64 if (libmail_gpg_stdout)
65 {
66 close(pipeout[0]);
67 close(pipeout[1]);
68 }
69
70 if (libmail_gpg_stdin)
71 {
72 close(pipein[0]);
73 close(pipein[1]);
74 }
75 return (-1);
76 }
77
78 signal(SIGCHLD, SIG_DFL);
79 p=libmail_gpg_pid=fork();
80 if (p < 0)
81 {
82 if (libmail_gpg_stderr)
83 {
84 close(pipeerr[0]);
85 close(pipeerr[1]);
86 }
87
88 if (libmail_gpg_stdout)
89 {
90 close(pipeout[0]);
91 close(pipeout[1]);
92 }
93 if (libmail_gpg_stdin)
94 {
95 close(pipein[0]);
96 close(pipein[1]);
97 }
98
99 return (-1);
100 }
101
102 if (p)
103 {
104 signal(SIGPIPE, SIG_IGN);
105
106 if (libmail_gpg_stderr)
107 {
108 close(pipeerr[1]);
109 *libmail_gpg_stderr=pipeerr[0];
110 }
111
112 if (libmail_gpg_stdout)
113 {
114 close(pipeout[1]);
115 *libmail_gpg_stdout=pipeout[0];
116 }
117
118 if (libmail_gpg_stdin)
119 {
120 close(pipein[0]);
121 *libmail_gpg_stdin=pipein[1];
122 }
123 return (0);
124 }
125
126 if (libmail_gpg_stderr)
127 {
128 dup2(pipeerr[1], 2);
129 close(pipeerr[0]);
130 close(pipeerr[1]);
131 }
132 else if (libmail_gpg_stdout)
133 {
134 dup2(pipeout[1], 2);
135 }
136
137 if (libmail_gpg_stdout)
138 {
139 dup2(pipeout[1], 1);
140 close(pipeout[0]);
141 close(pipeout[1]);
142 }
143
144 if (libmail_gpg_stdin)
145 {
146 dup2(pipein[0], 0);
147 close(pipein[0]);
148 close(pipein[1]);
149 }
150
151 if (gpgdir)
152 {
153 s=malloc(sizeof("GNUPGHOME=")+strlen(gpgdir));
154 if (!s)
155 {
156 perror("malloc");
157 exit(1);
158 }
159 strcat(strcpy(s, "GNUPGHOME="), gpgdir);
160 if (putenv(s) < 0)
161 {
162 perror("putenv");
163 exit(1);
164 }
165 }
166
167 {
168 const char *gpg=getenv("GPG");
169 if (!gpg || !*gpg)
170 gpg=GPG;
171
172 execv(gpg, argvec);
173 perror(gpg);
174 }
175 _exit(1);
176 return (0);
177 }
178
libmail_gpg_write(const char * p,size_t cnt,int (* stdout_func)(const char *,size_t,void *),int (* stderr_func)(const char *,size_t,void *),int (* timeout_func)(void *),unsigned timeout,void * voidarg)179 int libmail_gpg_write(const char *p, size_t cnt,
180 int (*stdout_func)(const char *, size_t, void *),
181 int (*stderr_func)(const char *, size_t, void *),
182 int (*timeout_func)(void *),
183 unsigned timeout,
184 void *voidarg)
185 {
186 char buf[BUFSIZ];
187
188 fd_set fdr, fdw;
189 struct timeval tv;
190
191 if (!timeout_func)
192 timeout=0;
193 while (cnt)
194 {
195 int maxfd=0;
196 int n;
197
198 FD_ZERO(&fdr);
199 FD_ZERO(&fdw);
200
201 FD_SET(libmail_gpg_stdin, &fdw);
202
203 if (libmail_gpg_stdout >= 0)
204 {
205 FD_SET(libmail_gpg_stdout, &fdr);
206 if (libmail_gpg_stdout > maxfd)
207 maxfd=libmail_gpg_stdout;
208 }
209
210 if (libmail_gpg_stderr >= 0)
211 {
212 FD_SET(libmail_gpg_stderr, &fdr);
213 if (libmail_gpg_stderr > maxfd)
214 maxfd=libmail_gpg_stderr;
215 }
216
217 tv.tv_usec=0;
218 tv.tv_sec=timeout;
219 n=select(maxfd+1, &fdr, &fdw, NULL, timeout ? &tv:NULL);
220 if (n == 0)
221 {
222 n=(*timeout_func)(voidarg);
223 if (n)
224 return(n);
225 continue;
226 }
227 if (n < 0)
228 continue;
229
230 if (FD_ISSET(libmail_gpg_stdin, &fdw))
231 {
232 int n=write(libmail_gpg_stdin, p, cnt);
233
234 if (n <= 0)
235 return (-1);
236
237 p += n;
238 cnt -= n;
239 }
240
241 if (libmail_gpg_stdout >= 0 &&
242 FD_ISSET(libmail_gpg_stdout, &fdr))
243 {
244 int n=read(libmail_gpg_stdout, buf, sizeof(buf));
245
246 if (n <= 0)
247 {
248 close(libmail_gpg_stdout);
249 libmail_gpg_stdout= -1;
250 }
251 else if (stdout_func &&
252 (n=(*stdout_func)(buf, n, voidarg)) != 0)
253 return (n);
254 }
255
256 if (libmail_gpg_stderr >= 0 &&
257 FD_ISSET(libmail_gpg_stderr, &fdr))
258 {
259 int n=read(libmail_gpg_stderr, buf, sizeof(buf));
260
261 if (n <= 0)
262 {
263 close(libmail_gpg_stderr);
264 libmail_gpg_stderr= -1;
265 }
266 else if (stderr_func &&
267 (n=(*stderr_func)(buf, n, voidarg)) != 0)
268 return (n);
269 }
270 }
271 return (0);
272 }
273
libmail_gpg_read(int (* stdout_func)(const char *,size_t,void *),int (* stderr_func)(const char *,size_t,void *),int (* timeout_func)(void *),unsigned timeout,void * voidarg)274 int libmail_gpg_read(int (*stdout_func)(const char *, size_t, void *),
275 int (*stderr_func)(const char *, size_t, void *),
276 int (*timeout_func)(void *),
277 unsigned timeout,
278 void *voidarg)
279 {
280 char buf[BUFSIZ];
281
282 fd_set fdr;
283 struct timeval tv;
284
285 if (libmail_gpg_stdin >= 0)
286 {
287 close(libmail_gpg_stdin);
288 libmail_gpg_stdin= -1;
289 }
290
291 if (!timeout_func)
292 timeout=0;
293
294 while ( libmail_gpg_stdout >= 0 || libmail_gpg_stderr >= 0)
295 {
296 int maxfd=0;
297 int n;
298
299 FD_ZERO(&fdr);
300
301 if (libmail_gpg_stdout >= 0)
302 {
303 FD_SET(libmail_gpg_stdout, &fdr);
304 if (libmail_gpg_stdout > maxfd)
305 maxfd=libmail_gpg_stdout;
306 }
307
308 if (libmail_gpg_stderr >= 0)
309 {
310 FD_SET(libmail_gpg_stderr, &fdr);
311 if (libmail_gpg_stderr > maxfd)
312 maxfd=libmail_gpg_stderr;
313 }
314
315 tv.tv_usec=0;
316 tv.tv_sec=timeout;
317 n=select(maxfd+1, &fdr, NULL, NULL, timeout ? &tv:NULL);
318
319 if (n == 0)
320 {
321 n=(*timeout_func)(voidarg);
322 if (n)
323 return(n);
324 continue;
325 }
326 if (n < 0)
327 continue;
328
329 if (libmail_gpg_stdout >= 0 &&
330 FD_ISSET(libmail_gpg_stdout, &fdr))
331 {
332 int n=read(libmail_gpg_stdout, buf, sizeof(buf));
333
334 if (n <= 0)
335 {
336 close(libmail_gpg_stdout);
337 libmail_gpg_stdout= -1;
338 }
339 else if (stdout_func &&
340 (n=(*stdout_func)(buf, n, voidarg)) != 0)
341 return (n);
342 }
343
344 if (libmail_gpg_stderr >= 0 &&
345 FD_ISSET(libmail_gpg_stderr, &fdr))
346 {
347 int n=read(libmail_gpg_stderr, buf, sizeof(buf));
348
349 if (n <= 0)
350 {
351 close(libmail_gpg_stderr);
352 libmail_gpg_stderr= -1;
353 }
354 else if (stderr_func &&
355 (n=(*stderr_func)(buf, n, voidarg)) != 0)
356 return (n);
357 }
358 }
359 return (0);
360 }
361