* configure.ac (AH_BOTTOM): Define EXEEXT_S.
[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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22
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
36
37 #include "util.h"
38 #include "i18n.h"
39 #include "exechelp.h"
40
41 /* Define to 1 do enable debugging.  */
42 #define DEBUG_W32_SPAWN 1
43
44
45 #ifdef _POSIX_OPEN_MAX
46 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
47 #else
48 #define MAX_OPEN_FDS 20
49 #endif
50
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
60
61
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
72
73
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)
79 {
80   int i, n;
81   const char *s;
82   char *buf, *p;
83
84   *cmdline = NULL;
85   n = strlen (pgmname);
86   for (i=0; (s=argv[i]); i++)
87     {
88       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
89       for (; *s; s++)
90         if (*s == '\"')
91           n++;  /* Need to double inner quotes.  */
92     }
93   n++;
94
95   buf = p = xtrymalloc (n);
96   if (!buf)
97     return gpg_error_from_errno (errno);
98
99   /* fixme: PGMNAME may not contain spaces etc. */
100   p = stpcpy (p, pgmname);
101   for (i=0; argv[i]; i++) 
102     {
103       if (!*argv[i]) /* Empty string. */
104         p = stpcpy (p, " \"\"");
105       else if (strpbrk (argv[i], " \t\n\v\f\""))
106         {
107           p = stpcpy (p, " \"");
108           for (s=argv[i]; *s; s++)
109             {
110               *p++ = *s;
111               if (*s == '\"')
112                 *p++ = *s;
113             }
114           *p++ = '\"';
115           *p = 0;
116         }
117       else
118         p = stpcpy (stpcpy (p, " "), argv[i]);
119     }
120
121   *cmdline= buf;
122   return 0;
123 }
124 #endif /*HAVE_W32_SYSTEM*/
125
126
127 #ifdef HAVE_W32_SYSTEM
128 /* Create  pipe where the write end is inheritable.  */
129 static int
130 create_inheritable_pipe (int filedes[2])
131 {
132   HANDLE r, w, h;
133   SECURITY_ATTRIBUTES sec_attr;
134
135   memset (&sec_attr, 0, sizeof sec_attr );
136   sec_attr.nLength = sizeof sec_attr;
137   sec_attr.bInheritHandle = FALSE;
138     
139   if (!CreatePipe (&r, &w, &sec_attr, 0))
140     return -1;
141
142   if (!DuplicateHandle (GetCurrentProcess(), w,
143                         GetCurrentProcess(), &h, 0,
144                         TRUE, DUPLICATE_SAME_ACCESS ))
145     {
146       log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
147       CloseHandle (r);
148       CloseHandle (w);
149       return -1;
150     }
151   CloseHandle (w);
152   w = h;
153
154   filedes[0] = handle_to_fd (r);
155   filedes[1] = handle_to_fd (w);
156   return 0;
157 }
158 #endif /*HAVE_W32_SYSTEM*/
159
160
161
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.
169
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)
176 {
177 #ifdef HAVE_W32_SYSTEM
178   gpg_error_t err;
179   SECURITY_ATTRIBUTES sec_attr;
180   PROCESS_INFORMATION pi = 
181     {
182       NULL,      /* Returns process handle.  */
183       0,         /* Returns primary thread handle.  */
184       0,         /* Returns pid.  */
185       0          /* Returns tid.  */
186     };
187   STARTUPINFO si;
188   int cr_flags;
189   char *cmdline;
190   int fd, fdout, rp[2];
191
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");
201
202   /* Prepare security attributes.  */
203   memset (&sec_attr, 0, sizeof sec_attr );
204   sec_attr.nLength = sizeof sec_attr;
205   sec_attr.bInheritHandle = FALSE;
206   
207   /* Build the command line.  */
208   err = build_w32_commandline (pgmname, argv, &cmdline);
209   if (err)
210     return err; 
211
212   /* Create a pipe.  */
213   if (create_inheritable_pipe (rp))
214     {
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;
219     }
220   
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]);
230
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.  */
245                       ))
246     {
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);
252     }
253   xfree (cmdline);
254   cmdline = NULL;
255
256   /* Close the other end of the pipe.  */
257   CloseHandle (fd_to_handle (rp[1]));
258   
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);
263
264   /* Process ha been created suspended; resume it now. */
265   ResumeThread (pi.hThread);
266   CloseHandle (pi.hThread); 
267
268   {
269     int x;
270
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 
275       {
276         log_debug ("_open_osfhandle %p yields %d\n", (void*)fd, x );
277         *statusfile = fdopen (x, "r");
278       }
279   }
280   if (!*statusfile)
281     {
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;
286     }
287
288   *pid = handle_to_pid (pi.hProcess);
289   return 0;
290
291 #else /* !HAVE_W32_SYSTEM */
292   gpg_error_t err;
293   int fd, fdout, rp[2];
294
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");
303
304   if (pipe (rp) == -1)
305     {
306       err = gpg_error_from_errno (errno);
307       log_error (_("error creating a pipe: %s\n"), strerror (errno));
308       return err;
309     }
310
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))
317     {
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;
323     }
324
325   if (!*pid)
326     { 
327       /* Child. */
328       char **arg_list;
329       int n, i, j;
330
331       /* Create the command line argument array.  */
332       for (i=0; argv[i]; i++)
333         ;
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];
342
343       /* Connect the infile to stdin. */
344       if (fd != 0 && dup2 (fd, 0) == -1)
345         log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
346
347       /* Connect the outfile to stdout. */
348       if (fdout != 1 && dup2 (fdout, 1) == -1)
349         log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
350       
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));
354
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;
362
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);
368     }
369
370   /* Parent. */
371   close (rp[1]);
372
373   *statusfile = fdopen (rp[0], "r");
374   if (!*statusfile)
375     {
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;
381     }
382
383   return 0;
384 #endif /* !HAVE_W32_SYSTEM */
385 }
386
387
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)
394 {
395   gpg_err_code_t ec;
396
397 #ifdef HAVE_W32_SYSTEM
398   HANDLE proc = fd_to_handle (pid);
399   int code;
400   DWORD exc;
401
402   if (pid == (pid_t)(-1))
403     return gpg_error (GPG_ERR_INV_VALUE);
404
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) 
410     {
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;
416
417       case WAIT_OBJECT_0:
418         if (!GetExitCodeProcess (proc, &exc))
419           {
420             log_error (_("error getting exit code of process %d: %s\n"),
421                          (int)pid, w32_strerror (-1) );
422             ec = GPG_ERR_GENERAL;
423           }
424         else if (exc)
425           {
426             log_error (_("error running `%s': exit status %d\n"),
427                        pgmname, (int)exc );
428             ec = GPG_ERR_GENERAL;
429           }
430         else
431           ec = 0;
432         break;
433
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;
439     }
440
441 #else /* !HAVE_W32_SYSTEM */
442   int i, status;
443
444   if (pid == (pid_t)(-1))
445     return gpg_error (GPG_ERR_INV_VALUE);
446
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)
451     ;
452 #endif
453   if (i == (pid_t)(-1))
454     {
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);
458     }
459   else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
460     {
461       log_error (_("error running `%s': probably not installed\n"), pgmname);
462       ec = GPG_ERR_CONFIGURATION;
463     }
464   else if (WIFEXITED (status) && WEXITSTATUS (status))
465     {
466       log_error (_("error running `%s': exit status %d\n"), pgmname,
467                  WEXITSTATUS (status));
468       ec = GPG_ERR_GENERAL;
469     }
470   else if (!WIFEXITED (status))
471     {
472       log_error (_("error running `%s': terminated\n"), pgmname);
473       ec = GPG_ERR_GENERAL;
474     }
475   else 
476     ec = 0;
477 #endif /* !HAVE_W32_SYSTEM */
478
479   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
480
481 }
482