2005-10-07 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / exechelp.c
blobdc0a6b0e13f554d1129d997c0f2bad94dab69549
1 /* exechelp.c - fork and exec helpers
2 * Copyright (C) 2004 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
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.
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.
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
21 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28 #include <signal.h>
29 #include <unistd.h>
30 #ifdef USE_GNU_PTH
31 #include <pth.h>
32 #endif
33 #ifndef HAVE_W32_SYSTEM
34 #include <sys/wait.h>
35 #endif
37 #include "util.h"
38 #include "i18n.h"
39 #include "exechelp.h"
41 /* Define to 1 do enable debugging. */
42 #define DEBUG_W32_SPAWN 1
45 #ifdef _POSIX_OPEN_MAX
46 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
47 #else
48 #define MAX_OPEN_FDS 20
49 #endif
51 /* We have the usual problem here: Some modules are linked against pth
52 and some are not. However we want to use pth_fork and pth_waitpid
53 here. Using a weak symbol works but is not portable - we should
54 provide a an explicit dummy pth module instead of using the
55 pragma. */
56 #ifndef _WIN32
57 #pragma weak pth_fork
58 #pragma weak pth_waitpid
59 #endif
62 #ifdef HAVE_W32_SYSTEM
63 /* We assume that a HANDLE can be represented by an int which should
64 be true for all i386 systems (HANDLE is defined as void *) and
65 these are the only systems for which Windows is available. Further
66 we assume that -1 denotes an invalid handle. */
67 # define fd_to_handle(a) ((HANDLE)(a))
68 # define handle_to_fd(a) ((int)(a))
69 # define pid_to_handle(a) ((HANDLE)(a))
70 # define handle_to_pid(a) ((int)(a))
71 #endif
74 #ifdef HAVE_W32_SYSTEM
75 /* Build a command line for use with W32's CreateProcess. On success
76 CMDLINE gets the address of a newly allocated string. */
77 static gpg_error_t
78 build_w32_commandline (const char *pgmname, const char **argv, char **cmdline)
80 int i, n;
81 const char *s;
82 char *buf, *p;
84 *cmdline = NULL;
85 n = strlen (pgmname);
86 for (i=0; (s=argv[i]); i++)
88 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
89 for (; *s; s++)
90 if (*s == '\"')
91 n++; /* Need to double inner quotes. */
93 n++;
95 buf = p = xtrymalloc (n);
96 if (!buf)
97 return gpg_error_from_errno (errno);
99 /* fixme: PGMNAME may not contain spaces etc. */
100 p = stpcpy (p, pgmname);
101 for (i=0; argv[i]; i++)
103 if (!*argv[i]) /* Empty string. */
104 p = stpcpy (p, " \"\"");
105 else if (strpbrk (argv[i], " \t\n\v\f\""))
107 p = stpcpy (p, " \"");
108 for (s=argv[i]; *s; s++)
110 *p++ = *s;
111 if (*s == '\"')
112 *p++ = *s;
114 *p++ = '\"';
115 *p = 0;
117 else
118 p = stpcpy (stpcpy (p, " "), argv[i]);
121 *cmdline= buf;
122 return 0;
124 #endif /*HAVE_W32_SYSTEM*/
127 #ifdef HAVE_W32_SYSTEM
128 /* Create pipe where the write end is inheritable. */
129 static int
130 create_inheritable_pipe (int filedes[2])
132 HANDLE r, w, h;
133 SECURITY_ATTRIBUTES sec_attr;
135 memset (&sec_attr, 0, sizeof sec_attr );
136 sec_attr.nLength = sizeof sec_attr;
137 sec_attr.bInheritHandle = FALSE;
139 if (!CreatePipe (&r, &w, &sec_attr, 0))
140 return -1;
142 if (!DuplicateHandle (GetCurrentProcess(), w,
143 GetCurrentProcess(), &h, 0,
144 TRUE, DUPLICATE_SAME_ACCESS ))
146 log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
147 CloseHandle (r);
148 CloseHandle (w);
149 return -1;
151 CloseHandle (w);
152 w = h;
154 filedes[0] = handle_to_fd (r);
155 filedes[1] = handle_to_fd (w);
156 return 0;
158 #endif /*HAVE_W32_SYSTEM*/
162 /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
163 stdin, write the output to OUTFILE, return a new stream in
164 STATUSFILE for stderr and the pid of the process in PID. The
165 arguments for the process are expected in the NULL terminated array
166 ARGV. The program name itself should not be included there. if
167 PREEXEC is not NULL, that function will be called right before the
168 exec.
170 Returns 0 on success or an error code. */
171 gpg_error_t
172 gnupg_spawn_process (const char *pgmname, const char *argv[],
173 FILE *infile, FILE *outfile,
174 void (*preexec)(void),
175 FILE **statusfile, pid_t *pid)
177 #ifdef HAVE_W32_SYSTEM
178 gpg_error_t err;
179 SECURITY_ATTRIBUTES sec_attr;
180 PROCESS_INFORMATION pi =
182 NULL, /* Returns process handle. */
183 0, /* Returns primary thread handle. */
184 0, /* Returns pid. */
185 0 /* Returns tid. */
187 STARTUPINFO si;
188 int cr_flags;
189 char *cmdline;
190 int fd, fdout, rp[2];
192 /* Setup return values. */
193 *statusfile = NULL;
194 *pid = (pid_t)(-1);
195 fflush (infile);
196 rewind (infile);
197 fd = _get_osfhandle (fileno (infile));
198 fdout = _get_osfhandle (fileno (outfile));
199 if (fd == -1 || fdout == -1)
200 log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
202 /* Prepare security attributes. */
203 memset (&sec_attr, 0, sizeof sec_attr );
204 sec_attr.nLength = sizeof sec_attr;
205 sec_attr.bInheritHandle = FALSE;
207 /* Build the command line. */
208 err = build_w32_commandline (pgmname, argv, &cmdline);
209 if (err)
210 return err;
212 /* Create a pipe. */
213 if (create_inheritable_pipe (rp))
215 err = gpg_error (GPG_ERR_GENERAL);
216 log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
217 xfree (cmdline);
218 return err;
221 /* Start the process. Note that we can't run the PREEXEC function
222 because this would change our own environment. */
223 memset (&si, 0, sizeof si);
224 si.cb = sizeof (si);
225 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
226 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
227 si.hStdInput = fd_to_handle (fd);
228 si.hStdOutput = fd_to_handle (fdout);
229 si.hStdError = fd_to_handle (rp[1]);
231 cr_flags = (CREATE_DEFAULT_ERROR_MODE
232 | GetPriorityClass (GetCurrentProcess ())
233 | CREATE_SUSPENDED);
234 log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
235 if (!CreateProcess (pgmname, /* Program to start. */
236 cmdline, /* Command line arguments. */
237 &sec_attr, /* Process security attributes. */
238 &sec_attr, /* Thread security attributes. */
239 TRUE, /* Inherit handles. */
240 cr_flags, /* Creation flags. */
241 NULL, /* Environment. */
242 NULL, /* Use current drive/directory. */
243 &si, /* Startup information. */
244 &pi /* Returns process information. */
247 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
248 xfree (cmdline);
249 CloseHandle (fd_to_handle (rp[0]));
250 CloseHandle (fd_to_handle (rp[1]));
251 return gpg_error (GPG_ERR_GENERAL);
253 xfree (cmdline);
254 cmdline = NULL;
256 /* Close the other end of the pipe. */
257 CloseHandle (fd_to_handle (rp[1]));
259 log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
260 " dwProcessID=%d dwThreadId=%d\n",
261 pi.hProcess, pi.hThread,
262 (int) pi.dwProcessId, (int) pi.dwThreadId);
264 /* Process ha been created suspended; resume it now. */
265 ResumeThread (pi.hThread);
266 CloseHandle (pi.hThread);
269 int x;
271 x = _open_osfhandle (rp[0], 0);
272 if (x == -1)
273 log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
274 else
276 log_debug ("_open_osfhandle %p yields %d\n", (void*)fd, x );
277 *statusfile = fdopen (x, "r");
280 if (!*statusfile)
282 err = gpg_error_from_errno (errno);
283 log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
284 CloseHandle (pi.hProcess);
285 return err;
288 *pid = handle_to_pid (pi.hProcess);
289 return 0;
291 #else /* !HAVE_W32_SYSTEM */
292 gpg_error_t err;
293 int fd, fdout, rp[2];
295 *statusfile = NULL;
296 *pid = (pid_t)(-1);
297 fflush (infile);
298 rewind (infile);
299 fd = fileno (infile);
300 fdout = fileno (outfile);
301 if (fd == -1 || fdout == -1)
302 log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
304 if (pipe (rp) == -1)
306 err = gpg_error_from_errno (errno);
307 log_error (_("error creating a pipe: %s\n"), strerror (errno));
308 return err;
311 #ifdef USE_GNU_PTH
312 *pid = pth_fork? pth_fork () : fork ();
313 #else
314 *pid = fork ();
315 #endif
316 if (*pid == (pid_t)(-1))
318 err = gpg_error_from_errno (errno);
319 log_error (_("error forking process: %s\n"), strerror (errno));
320 close (rp[0]);
321 close (rp[1]);
322 return err;
325 if (!*pid)
327 /* Child. */
328 char **arg_list;
329 int n, i, j;
331 /* Create the command line argument array. */
332 for (i=0; argv[i]; i++)
334 arg_list = xcalloc (i+2, sizeof *arg_list);
335 arg_list[0] = strrchr (pgmname, '/');
336 if (arg_list[0])
337 arg_list[0]++;
338 else
339 arg_list[0] = xstrdup (pgmname);
340 for (i=0,j=1; argv[i]; i++, j++)
341 arg_list[j] = (char*)argv[i];
343 /* Connect the infile to stdin. */
344 if (fd != 0 && dup2 (fd, 0) == -1)
345 log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
347 /* Connect the outfile to stdout. */
348 if (fdout != 1 && dup2 (fdout, 1) == -1)
349 log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
351 /* Connect stderr to our pipe. */
352 if (rp[1] != 2 && dup2 (rp[1], 2) == -1)
353 log_fatal ("dup2 stderr failed: %s\n", strerror (errno));
355 /* Close all other files. */
356 n = sysconf (_SC_OPEN_MAX);
357 if (n < 0)
358 n = MAX_OPEN_FDS;
359 for (i=3; i < n; i++)
360 close(i);
361 errno = 0;
363 if (preexec)
364 preexec ();
365 execv (pgmname, arg_list);
366 /* No way to print anything, as we have closed all streams. */
367 _exit (127);
370 /* Parent. */
371 close (rp[1]);
373 *statusfile = fdopen (rp[0], "r");
374 if (!*statusfile)
376 err = gpg_error_from_errno (errno);
377 log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
378 kill (*pid, SIGTERM);
379 *pid = (pid_t)(-1);
380 return err;
383 return 0;
384 #endif /* !HAVE_W32_SYSTEM */
388 /* Wait for the process identified by PID to terminate. PGMNAME should
389 be the same as suplieed to the spawn fucntion and is only used for
390 diagnostics. Returns 0 if the process succeded, GPG_ERR_GENERAL for
391 any failures of the spawned program or other error codes.*/
392 gpg_error_t
393 gnupg_wait_process (const char *pgmname, pid_t pid)
395 gpg_err_code_t ec;
397 #ifdef HAVE_W32_SYSTEM
398 HANDLE proc = fd_to_handle (pid);
399 int code;
400 DWORD exc;
402 if (pid == (pid_t)(-1))
403 return gpg_error (GPG_ERR_INV_VALUE);
405 /* FIXME: We should do a pth_waitpid here. However this has not yet
406 been implemented. A special W32 pth system call would even be
407 better. */
408 code = WaitForSingleObject (proc, INFINITE);
409 switch (code)
411 case WAIT_FAILED:
412 log_error (_("waiting for process %d to terminate failed: %s\n"),
413 (int)pid, w32_strerror (-1));
414 ec = GPG_ERR_GENERAL;
415 break;
417 case WAIT_OBJECT_0:
418 if (!GetExitCodeProcess (proc, &exc))
420 log_error (_("error getting exit code of process %d: %s\n"),
421 (int)pid, w32_strerror (-1) );
422 ec = GPG_ERR_GENERAL;
424 else if (exc)
426 log_error (_("error running `%s': exit status %d\n"),
427 pgmname, (int)exc );
428 ec = GPG_ERR_GENERAL;
430 else
431 ec = 0;
432 break;
434 default:
435 log_error ("WaitForSingleObject returned unexpected "
436 "code %d for pid %d\n", code, (int)pid );
437 ec = GPG_ERR_GENERAL;
438 break;
441 #else /* !HAVE_W32_SYSTEM */
442 int i, status;
444 if (pid == (pid_t)(-1))
445 return gpg_error (GPG_ERR_INV_VALUE);
447 #ifdef USE_GNU_PTH
448 i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
449 #else
450 while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
452 #endif
453 if (i == (pid_t)(-1))
455 log_error (_("waiting for process %d to terminate failed: %s\n"),
456 (int)pid, strerror (errno));
457 ec = gpg_err_code_from_errno (errno);
459 else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
461 log_error (_("error running `%s': probably not installed\n"), pgmname);
462 ec = GPG_ERR_CONFIGURATION;
464 else if (WIFEXITED (status) && WEXITSTATUS (status))
466 log_error (_("error running `%s': exit status %d\n"), pgmname,
467 WEXITSTATUS (status));
468 ec = GPG_ERR_GENERAL;
470 else if (!WIFEXITED (status))
472 log_error (_("error running `%s': terminated\n"), pgmname);
473 ec = GPG_ERR_GENERAL;
475 else
476 ec = 0;
477 #endif /* !HAVE_W32_SYSTEM */
479 return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);