7da7dbd50d35ed62837a842bbc72af6be8b2864a
[gnupg.git] / common / exechelp.c
1 /* exechelp.c - fork and exec helpers
2  *      Copyright (C) 2004, 2007 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 3 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <signal.h>
28 #include <unistd.h> 
29 #include <fcntl.h>
30
31 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
32 #undef HAVE_PTH
33 #undef USE_GNU_PTH
34 #endif
35
36 #ifdef USE_GNU_PTH      
37 #include <pth.h>
38 #endif
39 #ifndef HAVE_W32_SYSTEM
40 #include <sys/wait.h>
41 #endif
42
43 #include "util.h"
44 #include "i18n.h"
45 #include "exechelp.h"
46
47 /* Define to 1 do enable debugging.  */
48 #define DEBUG_W32_SPAWN 1
49
50
51 #ifdef _POSIX_OPEN_MAX
52 #define MAX_OPEN_FDS _POSIX_OPEN_MAX
53 #else
54 #define MAX_OPEN_FDS 20
55 #endif
56
57 /* We have the usual problem here: Some modules are linked against pth
58    and some are not.  However we want to use pth_fork and pth_waitpid
59    here. Using a weak symbol works but is not portable - we should
60    provide a an explicit dummy pth module instead of using the
61    pragma.  */ 
62 #ifndef _WIN32
63 #pragma weak pth_fork
64 #pragma weak pth_waitpid
65 #endif
66
67 #ifdef HAVE_W32_SYSTEM
68 /* It seems Vista doesn't grok X_OK and so fails access() tests.
69    Previous versions interpreted X_OK as F_OK anyway, so we'll just
70    use F_OK directly. */
71 #undef X_OK
72 #define X_OK F_OK
73 #endif /* HAVE_W32_SYSTEM */
74
75
76 #ifdef HAVE_W32_SYSTEM
77 /* We assume that a HANDLE can be represented by an int which should
78    be true for all i386 systems (HANDLE is defined as void *) and
79    these are the only systems for which Windows is available.  Further
80    we assume that -1 denotes an invalid handle.  */
81 # define fd_to_handle(a)  ((HANDLE)(a))
82 # define handle_to_fd(a)  ((int)(a))
83 # define pid_to_handle(a) ((HANDLE)(a))
84 # define handle_to_pid(a) ((int)(a))
85 #endif
86
87
88 #ifdef HAVE_W32_SYSTEM
89 /* Helper function to build_w32_commandline. */
90 static char *
91 build_w32_commandline_copy (char *buffer, const char *string)
92 {
93   char *p = buffer;
94   const char *s;
95
96   if (!*string) /* Empty string. */
97     p = stpcpy (p, "\"\"");
98   else if (strpbrk (string, " \t\n\v\f\""))
99     {
100       /* Need top do some kind of quoting.  */
101       p = stpcpy (p, "\"");
102       for (s=string; *s; s++)
103         {
104           *p++ = *s;
105           if (*s == '\"')
106             *p++ = *s;
107         }
108       *p++ = '\"';
109       *p = 0;
110     }
111   else
112     p = stpcpy (p, string);
113
114   return p;
115 }
116
117 /* Build a command line for use with W32's CreateProcess.  On success
118    CMDLINE gets the address of a newly allocated string.  */
119 static gpg_error_t
120 build_w32_commandline (const char *pgmname, const char * const *argv, 
121                        char **cmdline)
122 {
123   int i, n;
124   const char *s;
125   char *buf, *p;
126
127   *cmdline = NULL;
128   n = 0;
129   s = pgmname;
130   n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
131   for (; *s; s++)
132     if (*s == '\"')
133       n++;  /* Need to double inner quotes.  */
134   for (i=0; (s=argv[i]); i++)
135     {
136       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
137       for (; *s; s++)
138         if (*s == '\"')
139           n++;  /* Need to double inner quotes.  */
140     }
141   n++;
142
143   buf = p = xtrymalloc (n);
144   if (!buf)
145     return gpg_error_from_syserror ();
146
147   p = build_w32_commandline_copy (p, pgmname);
148   for (i=0; argv[i]; i++) 
149     {
150       *p++ = ' ';
151       p = build_w32_commandline_copy (p, argv[i]);
152     }
153
154   *cmdline= buf;
155   return 0;
156 }
157 #endif /*HAVE_W32_SYSTEM*/
158
159
160 #ifdef HAVE_W32_SYSTEM
161 /* Create  pipe where the write end is inheritable.  */
162 static int
163 create_inheritable_pipe (int filedes[2])
164 {
165   HANDLE r, w, h;
166   SECURITY_ATTRIBUTES sec_attr;
167
168   memset (&sec_attr, 0, sizeof sec_attr );
169   sec_attr.nLength = sizeof sec_attr;
170   sec_attr.bInheritHandle = FALSE;
171     
172   if (!CreatePipe (&r, &w, &sec_attr, 0))
173     return -1;
174
175   if (!DuplicateHandle (GetCurrentProcess(), w,
176                         GetCurrentProcess(), &h, 0,
177                         TRUE, DUPLICATE_SAME_ACCESS ))
178     {
179       log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
180       CloseHandle (r);
181       CloseHandle (w);
182       return -1;
183     }
184   CloseHandle (w);
185   w = h;
186
187   filedes[0] = handle_to_fd (r);
188   filedes[1] = handle_to_fd (w);
189   return 0;
190 }
191 #endif /*HAVE_W32_SYSTEM*/
192
193
194 #ifdef HAVE_W32_SYSTEM
195 static HANDLE
196 w32_open_null (int for_write)
197 {
198   HANDLE hfile;
199
200   hfile = CreateFile ("nul",
201                       for_write? GENERIC_WRITE : GENERIC_READ,
202                       FILE_SHARE_READ | FILE_SHARE_WRITE,
203                       NULL, OPEN_EXISTING, 0, NULL);
204   if (hfile == INVALID_HANDLE_VALUE)
205     log_debug ("can't open `nul': %s\n", w32_strerror (-1));
206   return hfile;
207 }
208 #endif /*HAVE_W32_SYSTEM*/
209
210
211 #ifndef HAVE_W32_SYSTEM
212 /* The exec core used right after the fork. This will never return. */
213 static void
214 do_exec (const char *pgmname, const char *argv[],
215          int fd_in, int fd_out, int fd_err,
216          void (*preexec)(void) )
217 {
218   char **arg_list;
219   int n, i, j;
220   int fds[3];
221
222   fds[0] = fd_in;
223   fds[1] = fd_out;
224   fds[2] = fd_err;
225
226   /* Create the command line argument array.  */
227   i = 0;
228   if (argv)
229     while (argv[i])
230       i++;
231   arg_list = xcalloc (i+2, sizeof *arg_list);
232   arg_list[0] = strrchr (pgmname, '/');
233   if (arg_list[0])
234     arg_list[0]++;
235   else
236     arg_list[0] = xstrdup (pgmname);
237   if (argv)
238     for (i=0,j=1; argv[i]; i++, j++)
239       arg_list[j] = (char*)argv[i];
240
241   /* Connect the standard files. */
242   for (i=0; i <= 2; i++)
243     {
244       if (fds[i] == -1 )
245         {
246           fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
247           if (fds[i] == -1)
248             log_fatal ("failed to open `%s': %s\n",
249                        "/dev/null", strerror (errno));
250         }
251       else if (fds[i] != i && dup2 (fds[i], i) == -1)
252         log_fatal ("dup2 std%s failed: %s\n",
253                    i==0?"in":i==1?"out":"err", strerror (errno));
254     }
255
256   /* Close all other files. */
257   n = sysconf (_SC_OPEN_MAX);
258   if (n < 0)
259     n = MAX_OPEN_FDS;
260   for (i=3; i < n; i++)
261     close(i);
262   errno = 0;
263   
264   if (preexec)
265     preexec ();
266   execv (pgmname, arg_list);
267   /* No way to print anything, as we have closed all streams. */
268   _exit (127);
269 }
270 #endif /*!HAVE_W32_SYSTEM*/
271
272
273 /* Portable function to create a pipe.  Under Windows the write end is
274    inheritable.  */
275 gpg_error_t
276 gnupg_create_inbound_pipe (int filedes[2])
277 {
278   gpg_error_t err = 0;
279 #if HAVE_W32_SYSTEM
280   int fds[2];
281
282   filedes[0] = filedes[1] = -1;
283   err = gpg_error (GPG_ERR_GENERAL);
284   if (!create_inheritable_pipe (fds))
285     {
286       filedes[0] = _open_osfhandle (fds[0], 0);
287       if (filedes[0] == -1)
288         {
289           log_error ("failed to translate osfhandle %p\n", (void*)fds[0]);
290           CloseHandle (fd_to_handle (fds[1]));
291         }
292       else 
293         {
294           filedes[1] = _open_osfhandle (fds[1], 1);
295           if (filedes[1] == -1)
296             {
297               log_error ("failed to translate osfhandle %p\n", (void*)fds[1]);
298               close (filedes[0]);
299               filedes[0] = -1;
300               CloseHandle (fd_to_handle (fds[1]));
301             }
302           else
303             err = 0;
304         }
305     }
306 #else
307   if (pipe (filedes) == -1)
308     {
309       err = gpg_error_from_syserror ();
310       filedes[0] = filedes[1] = -1;
311     }
312 #endif
313   return err;
314 }
315
316
317 /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
318    stdin, write the output to OUTFILE, return a new stream in
319    STATUSFILE for stderr and the pid of the process in PID. The
320    arguments for the process are expected in the NULL terminated array
321    ARGV.  The program name itself should not be included there.  If
322    PREEXEC is not NULL, that function will be called right before the
323    exec.  Calling gnupg_wait_process is required.
324
325    Returns 0 on success or an error code. */
326 gpg_error_t
327 gnupg_spawn_process (const char *pgmname, const char *argv[],
328                      FILE *infile, FILE *outfile,
329                      void (*preexec)(void),
330                      FILE **statusfile, pid_t *pid)
331 {
332 #ifdef HAVE_W32_SYSTEM
333   gpg_error_t err;
334   SECURITY_ATTRIBUTES sec_attr;
335   PROCESS_INFORMATION pi = 
336     {
337       NULL,      /* Returns process handle.  */
338       0,         /* Returns primary thread handle.  */
339       0,         /* Returns pid.  */
340       0          /* Returns tid.  */
341     };
342   STARTUPINFO si;
343   int cr_flags;
344   char *cmdline;
345   int fd, fdout, rp[2];
346
347   /* Setup return values.  */
348   *statusfile = NULL;
349   *pid = (pid_t)(-1);
350   fflush (infile);
351   rewind (infile);
352   fd = _get_osfhandle (fileno (infile));
353   fdout = _get_osfhandle (fileno (outfile));
354   if (fd == -1 || fdout == -1)
355     log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
356
357   /* Prepare security attributes.  */
358   memset (&sec_attr, 0, sizeof sec_attr );
359   sec_attr.nLength = sizeof sec_attr;
360   sec_attr.bInheritHandle = FALSE;
361   
362   /* Build the command line.  */
363   err = build_w32_commandline (pgmname, argv, &cmdline);
364   if (err)
365     return err; 
366
367   /* Create a pipe.  */
368   if (create_inheritable_pipe (rp))
369     {
370       err = gpg_error (GPG_ERR_GENERAL);
371       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
372       xfree (cmdline);
373       return err;
374     }
375   
376   /* Start the process.  Note that we can't run the PREEXEC function
377      because this would change our own environment. */
378   memset (&si, 0, sizeof si);
379   si.cb = sizeof (si);
380   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
381   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
382   si.hStdInput  = fd_to_handle (fd);
383   si.hStdOutput = fd_to_handle (fdout);
384   si.hStdError  = fd_to_handle (rp[1]);
385
386   cr_flags = (CREATE_DEFAULT_ERROR_MODE
387               | GetPriorityClass (GetCurrentProcess ())
388               | CREATE_SUSPENDED); 
389   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
390   if (!CreateProcess (pgmname,       /* Program to start.  */
391                       cmdline,       /* Command line arguments.  */
392                       &sec_attr,     /* Process security attributes.  */
393                       &sec_attr,     /* Thread security attributes.  */
394                       TRUE,          /* Inherit handles.  */
395                       cr_flags,      /* Creation flags.  */
396                       NULL,          /* Environment.  */
397                       NULL,          /* Use current drive/directory.  */
398                       &si,           /* Startup information. */
399                       &pi            /* Returns process information.  */
400                       ))
401     {
402       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
403       xfree (cmdline);
404       CloseHandle (fd_to_handle (rp[0]));
405       CloseHandle (fd_to_handle (rp[1]));
406       return gpg_error (GPG_ERR_GENERAL);
407     }
408   xfree (cmdline);
409   cmdline = NULL;
410
411   /* Close the other end of the pipe.  */
412   CloseHandle (fd_to_handle (rp[1]));
413   
414   log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
415              " dwProcessID=%d dwThreadId=%d\n",
416              pi.hProcess, pi.hThread,
417              (int) pi.dwProcessId, (int) pi.dwThreadId);
418
419   /* Process has been created suspended; resume it now. */
420   ResumeThread (pi.hThread);
421   CloseHandle (pi.hThread); 
422
423   {
424     int x;
425
426     x = _open_osfhandle (rp[0], 0);
427     if (x == -1)
428       log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
429     else 
430       *statusfile = fdopen (x, "r");
431   }
432   if (!*statusfile)
433     {
434       err = gpg_error_from_syserror ();
435       log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
436       CloseHandle (pi.hProcess);
437       return err;
438     }
439
440   *pid = handle_to_pid (pi.hProcess);
441   return 0;
442
443 #else /* !HAVE_W32_SYSTEM */
444   gpg_error_t err;
445   int fd, fdout, rp[2];
446
447   *statusfile = NULL;
448   *pid = (pid_t)(-1);
449   fflush (infile);
450   rewind (infile);
451   fd = fileno (infile);
452   fdout = fileno (outfile);
453   if (fd == -1 || fdout == -1)
454     log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
455
456   if (pipe (rp) == -1)
457     {
458       err = gpg_error_from_syserror ();
459       log_error (_("error creating a pipe: %s\n"), strerror (errno));
460       return err;
461     }
462
463 #ifdef USE_GNU_PTH      
464   *pid = pth_fork? pth_fork () : fork ();
465 #else
466   *pid = fork ();
467 #endif
468   if (*pid == (pid_t)(-1))
469     {
470       err = gpg_error_from_syserror ();
471       log_error (_("error forking process: %s\n"), strerror (errno));
472       close (rp[0]);
473       close (rp[1]);
474       return err;
475     }
476
477   if (!*pid)
478     { 
479       gcry_control (GCRYCTL_TERM_SECMEM);
480       /* Run child. */
481       do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
482       /*NOTREACHED*/
483     }
484
485   /* Parent. */
486   close (rp[1]);
487
488   *statusfile = fdopen (rp[0], "r");
489   if (!*statusfile)
490     {
491       err = gpg_error_from_syserror ();
492       log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
493       kill (*pid, SIGTERM);
494       *pid = (pid_t)(-1);
495       return err;
496     }
497
498   return 0;
499 #endif /* !HAVE_W32_SYSTEM */
500 }
501
502
503
504 /* Simplified version of gnupg_spawn_process.  This function forks and
505    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
506    and ERRFD to stderr (any of them may be -1 to connect them to
507    /dev/null).  The arguments for the process are expected in the NULL
508    terminated array ARGV.  The program name itself should not be
509    included there.  Calling gnupg_wait_process is required.
510
511    Returns 0 on success or an error code. */
512 gpg_error_t
513 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
514                         int infd, int outfd, int errfd, pid_t *pid)
515 {
516 #ifdef HAVE_W32_SYSTEM
517   gpg_error_t err;
518   SECURITY_ATTRIBUTES sec_attr;
519   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
520   STARTUPINFO si;
521   char *cmdline;
522   int i;
523   HANDLE stdhd[3];
524
525   /* Setup return values.  */
526   *pid = (pid_t)(-1);
527
528   /* Prepare security attributes.  */
529   memset (&sec_attr, 0, sizeof sec_attr );
530   sec_attr.nLength = sizeof sec_attr;
531   sec_attr.bInheritHandle = FALSE;
532   
533   /* Build the command line.  */
534   err = build_w32_commandline (pgmname, argv, &cmdline);
535   if (err)
536     return err; 
537
538   memset (&si, 0, sizeof si);
539   si.cb = sizeof (si);
540   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
541   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
542   stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
543   stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
544   stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
545   si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
546   si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
547   si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
548
549   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
550   if (!CreateProcess (pgmname,       /* Program to start.  */
551                       cmdline,       /* Command line arguments.  */
552                       &sec_attr,     /* Process security attributes.  */
553                       &sec_attr,     /* Thread security attributes.  */
554                       TRUE,          /* Inherit handles.  */
555                       (CREATE_DEFAULT_ERROR_MODE
556                        | GetPriorityClass (GetCurrentProcess ())
557                        | CREATE_SUSPENDED),
558                       NULL,          /* Environment.  */
559                       NULL,          /* Use current drive/directory.  */
560                       &si,           /* Startup information. */
561                       &pi            /* Returns process information.  */
562                       ))
563     {
564       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
565       err = gpg_error (GPG_ERR_GENERAL);
566     }
567   else
568     err = 0;
569   xfree (cmdline);
570   for (i=0; i < 3; i++)
571     if (stdhd[i] != INVALID_HANDLE_VALUE)
572       CloseHandle (stdhd[i]);
573   if (err)
574     return err;
575
576   log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
577              " dwProcessID=%d dwThreadId=%d\n",
578              pi.hProcess, pi.hThread,
579              (int) pi.dwProcessId, (int) pi.dwThreadId);
580
581   /* Process has been created suspended; resume it now. */
582   ResumeThread (pi.hThread);
583   CloseHandle (pi.hThread); 
584
585   *pid = handle_to_pid (pi.hProcess);
586   return 0;
587
588 #else /* !HAVE_W32_SYSTEM */
589   gpg_error_t err;
590
591 #ifdef USE_GNU_PTH      
592   *pid = pth_fork? pth_fork () : fork ();
593 #else
594   *pid = fork ();
595 #endif
596   if (*pid == (pid_t)(-1))
597     {
598       err = gpg_error_from_syserror ();
599       log_error (_("error forking process: %s\n"), strerror (errno));
600       return err;
601     }
602
603   if (!*pid)
604     { 
605       gcry_control (GCRYCTL_TERM_SECMEM);
606       /* Run child. */
607       do_exec (pgmname, argv, infd, outfd, errfd, NULL);
608       /*NOTREACHED*/
609     }
610
611   return 0;
612 #endif /* !HAVE_W32_SYSTEM */
613 }
614
615
616 /* Wait for the process identified by PID to terminate. PGMNAME should
617    be the same as supplied to the spawn function and is only used for
618    diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL
619    for any failures of the spawned program or other error codes.  If
620    EXITCODE is not NULL the exit code of the process is stored at this
621    address or -1 if it could not be retrieved. */
622 gpg_error_t
623 gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
624 {
625   gpg_err_code_t ec;
626
627 #ifdef HAVE_W32_SYSTEM
628   HANDLE proc = fd_to_handle (pid);
629   int code;
630   DWORD exc;
631
632   if (exitcode)
633     *exitcode = -1;
634
635   if (pid == (pid_t)(-1))
636     return gpg_error (GPG_ERR_INV_VALUE);
637
638   /* FIXME: We should do a pth_waitpid here.  However this has not yet
639      been implemented.  A special W32 pth system call would even be
640      better.  */
641   code = WaitForSingleObject (proc, INFINITE);
642   switch (code) 
643     {
644       case WAIT_FAILED:
645         log_error (_("waiting for process %d to terminate failed: %s\n"),
646                    (int)pid, w32_strerror (-1));
647         ec = GPG_ERR_GENERAL;
648         break;
649
650       case WAIT_OBJECT_0:
651         if (!GetExitCodeProcess (proc, &exc))
652           {
653             log_error (_("error getting exit code of process %d: %s\n"),
654                          (int)pid, w32_strerror (-1) );
655             ec = GPG_ERR_GENERAL;
656           }
657         else if (exc)
658           {
659             log_error (_("error running `%s': exit status %d\n"),
660                        pgmname, (int)exc );
661             if (exitcode)
662               *exitcode = (int)exc;
663             ec = GPG_ERR_GENERAL;
664           }
665         else
666           {
667             if (exitcode)
668               *exitcode = 0;
669             ec = 0;
670           }
671         CloseHandle (proc);
672         break;
673
674       default:
675         log_error ("WaitForSingleObject returned unexpected "
676                    "code %d for pid %d\n", code, (int)pid );
677         ec = GPG_ERR_GENERAL;
678         break;
679     }
680
681 #else /* !HAVE_W32_SYSTEM */
682   int i, status;
683
684   if (exitcode)
685     *exitcode = -1;
686
687   if (pid == (pid_t)(-1))
688     return gpg_error (GPG_ERR_INV_VALUE);
689
690 #ifdef USE_GNU_PTH
691   i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
692 #else
693   while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
694     ;
695 #endif
696   if (i == (pid_t)(-1))
697     {
698       log_error (_("waiting for process %d to terminate failed: %s\n"),
699                  (int)pid, strerror (errno));
700       ec = gpg_err_code_from_errno (errno);
701     }
702   else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
703     {
704       log_error (_("error running `%s': probably not installed\n"), pgmname);
705       ec = GPG_ERR_CONFIGURATION;
706     }
707   else if (WIFEXITED (status) && WEXITSTATUS (status))
708     {
709       log_error (_("error running `%s': exit status %d\n"), pgmname,
710                  WEXITSTATUS (status));
711       if (exitcode)
712         *exitcode = WEXITSTATUS (status);
713       ec = GPG_ERR_GENERAL;
714     }
715   else if (!WIFEXITED (status))
716     {
717       log_error (_("error running `%s': terminated\n"), pgmname);
718       ec = GPG_ERR_GENERAL;
719     }
720   else 
721     {
722       if (exitcode)
723         *exitcode = 0;
724       ec = 0;
725     }
726 #endif /* !HAVE_W32_SYSTEM */
727
728   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
729 }
730
731
732 /* Spawn a new process and immediatley detach from it.  The name of
733    the program to exec is PGMNAME and its arguments are in ARGV (the
734    programname is automatically passed as first argument).
735    Environment strings in ENVP are set.  An error is returned if
736    pgmname is not executable; to make this work it is necessary to
737    provide an absolute file name.  All standard file descriptors are
738    connected to /dev/null. */
739 gpg_error_t
740 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
741                               const char *envp[] )
742 {
743 #ifdef HAVE_W32_SYSTEM
744   gpg_error_t err;
745   SECURITY_ATTRIBUTES sec_attr;
746   PROCESS_INFORMATION pi = 
747     {
748       NULL,      /* Returns process handle.  */
749       0,         /* Returns primary thread handle.  */
750       0,         /* Returns pid.  */
751       0          /* Returns tid.  */
752     };
753   STARTUPINFO si;
754   int cr_flags;
755   char *cmdline;
756
757
758   /* FIXME: We don't make use of ENVP yet.  It is currently only used
759      to pass the GPG_AGENT_INFO variable to gpg-agent.  As the default
760      on windows is to use a standard socket, this does not really
761      matter.  */
762
763
764   if (access (pgmname, X_OK))
765     return gpg_error_from_syserror ();
766
767   /* Prepare security attributes.  */
768   memset (&sec_attr, 0, sizeof sec_attr );
769   sec_attr.nLength = sizeof sec_attr;
770   sec_attr.bInheritHandle = FALSE;
771   
772   /* Build the command line.  */
773   err = build_w32_commandline (pgmname, argv, &cmdline);
774   if (err)
775     return err; 
776
777   /* Start the process.  */
778   memset (&si, 0, sizeof si);
779   si.cb = sizeof (si);
780   si.dwFlags = STARTF_USESHOWWINDOW;
781   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
782
783   cr_flags = (CREATE_DEFAULT_ERROR_MODE
784               | GetPriorityClass (GetCurrentProcess ())
785               | CREATE_NEW_PROCESS_GROUP
786               | DETACHED_PROCESS); 
787   log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n",
788              pgmname, cmdline);
789   if (!CreateProcess (pgmname,       /* Program to start.  */
790                       cmdline,       /* Command line arguments.  */
791                       &sec_attr,     /* Process security attributes.  */
792                       &sec_attr,     /* Thread security attributes.  */
793                       FALSE,         /* Inherit handles.  */
794                       cr_flags,      /* Creation flags.  */
795                       NULL,          /* Environment.  */
796                       NULL,          /* Use current drive/directory.  */
797                       &si,           /* Startup information. */
798                       &pi            /* Returns process information.  */
799                       ))
800     {
801       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
802       xfree (cmdline);
803       return gpg_error (GPG_ERR_GENERAL);
804     }
805   xfree (cmdline);
806   cmdline = NULL;
807
808   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
809              " dwProcessID=%d dwThreadId=%d\n",
810              pi.hProcess, pi.hThread,
811              (int) pi.dwProcessId, (int) pi.dwThreadId);
812
813   CloseHandle (pi.hThread); 
814
815   return 0;
816
817 #else
818   pid_t pid;
819   int i;
820
821   if (getuid() != geteuid())
822     return gpg_error (GPG_ERR_BUG);
823
824   if (access (pgmname, X_OK))
825     return gpg_error_from_syserror ();
826
827 #ifdef USE_GNU_PTH      
828   pid = pth_fork? pth_fork () : fork ();
829 #else
830   pid = fork ();
831 #endif
832   if (pid == (pid_t)(-1))
833     {
834       log_error (_("error forking process: %s\n"), strerror (errno));
835       return gpg_error_from_syserror ();
836     }
837   if (!pid)
838     {
839       gcry_control (GCRYCTL_TERM_SECMEM);
840       if (setsid() == -1 || chdir ("/"))
841         _exit (1);
842       pid = fork (); /* Double fork to let init takes over the new child. */
843       if (pid == (pid_t)(-1))
844         _exit (1);
845       if (pid)
846         _exit (0);  /* Let the parent exit immediately. */
847
848       if (envp)
849         for (i=0; envp[i]; i++)
850           putenv (xstrdup (envp[i]));
851       
852       do_exec (pgmname, argv, -1, -1, -1, NULL);
853
854       /*NOTREACHED*/
855     }
856   
857   if (waitpid (pid, NULL, 0) == -1)
858     log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
859                strerror (errno));
860
861   return 0;
862 #endif /* !HAVE_W32_SYSTEM*/
863 }