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