4ec481f99931d8c728769c9b3aa00ac587c2870a
[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 /* Fork and exec the PGMNAME, connect the file descriptor of INFILE to
274    stdin, write the output to OUTFILE, return a new stream in
275    STATUSFILE for stderr and the pid of the process in PID. The
276    arguments for the process are expected in the NULL terminated array
277    ARGV.  The program name itself should not be included there.  If
278    PREEXEC is not NULL, that function will be called right before the
279    exec.  Calling gnupg_wait_process is required.
280
281    Returns 0 on success or an error code. */
282 gpg_error_t
283 gnupg_spawn_process (const char *pgmname, const char *argv[],
284                      FILE *infile, FILE *outfile,
285                      void (*preexec)(void),
286                      FILE **statusfile, pid_t *pid)
287 {
288 #ifdef HAVE_W32_SYSTEM
289   gpg_error_t err;
290   SECURITY_ATTRIBUTES sec_attr;
291   PROCESS_INFORMATION pi = 
292     {
293       NULL,      /* Returns process handle.  */
294       0,         /* Returns primary thread handle.  */
295       0,         /* Returns pid.  */
296       0          /* Returns tid.  */
297     };
298   STARTUPINFO si;
299   int cr_flags;
300   char *cmdline;
301   int fd, fdout, rp[2];
302
303   /* Setup return values.  */
304   *statusfile = NULL;
305   *pid = (pid_t)(-1);
306   fflush (infile);
307   rewind (infile);
308   fd = _get_osfhandle (fileno (infile));
309   fdout = _get_osfhandle (fileno (outfile));
310   if (fd == -1 || fdout == -1)
311     log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
312
313   /* Prepare security attributes.  */
314   memset (&sec_attr, 0, sizeof sec_attr );
315   sec_attr.nLength = sizeof sec_attr;
316   sec_attr.bInheritHandle = FALSE;
317   
318   /* Build the command line.  */
319   err = build_w32_commandline (pgmname, argv, &cmdline);
320   if (err)
321     return err; 
322
323   /* Create a pipe.  */
324   if (create_inheritable_pipe (rp))
325     {
326       err = gpg_error (GPG_ERR_GENERAL);
327       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
328       xfree (cmdline);
329       return err;
330     }
331   
332   /* Start the process.  Note that we can't run the PREEXEC function
333      because this would change our own environment. */
334   memset (&si, 0, sizeof si);
335   si.cb = sizeof (si);
336   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
337   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
338   si.hStdInput  = fd_to_handle (fd);
339   si.hStdOutput = fd_to_handle (fdout);
340   si.hStdError  = fd_to_handle (rp[1]);
341
342   cr_flags = (CREATE_DEFAULT_ERROR_MODE
343               | GetPriorityClass (GetCurrentProcess ())
344               | CREATE_SUSPENDED); 
345   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
346   if (!CreateProcess (pgmname,       /* Program to start.  */
347                       cmdline,       /* Command line arguments.  */
348                       &sec_attr,     /* Process security attributes.  */
349                       &sec_attr,     /* Thread security attributes.  */
350                       TRUE,          /* Inherit handles.  */
351                       cr_flags,      /* Creation flags.  */
352                       NULL,          /* Environment.  */
353                       NULL,          /* Use current drive/directory.  */
354                       &si,           /* Startup information. */
355                       &pi            /* Returns process information.  */
356                       ))
357     {
358       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
359       xfree (cmdline);
360       CloseHandle (fd_to_handle (rp[0]));
361       CloseHandle (fd_to_handle (rp[1]));
362       return gpg_error (GPG_ERR_GENERAL);
363     }
364   xfree (cmdline);
365   cmdline = NULL;
366
367   /* Close the other end of the pipe.  */
368   CloseHandle (fd_to_handle (rp[1]));
369   
370   log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
371              " dwProcessID=%d dwThreadId=%d\n",
372              pi.hProcess, pi.hThread,
373              (int) pi.dwProcessId, (int) pi.dwThreadId);
374
375   /* Process has been created suspended; resume it now. */
376   ResumeThread (pi.hThread);
377   CloseHandle (pi.hThread); 
378
379   {
380     int x;
381
382     x = _open_osfhandle (rp[0], 0);
383     if (x == -1)
384       log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
385     else 
386       *statusfile = fdopen (x, "r");
387   }
388   if (!*statusfile)
389     {
390       err = gpg_error_from_syserror ();
391       log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
392       CloseHandle (pi.hProcess);
393       return err;
394     }
395
396   *pid = handle_to_pid (pi.hProcess);
397   return 0;
398
399 #else /* !HAVE_W32_SYSTEM */
400   gpg_error_t err;
401   int fd, fdout, rp[2];
402
403   *statusfile = NULL;
404   *pid = (pid_t)(-1);
405   fflush (infile);
406   rewind (infile);
407   fd = fileno (infile);
408   fdout = fileno (outfile);
409   if (fd == -1 || fdout == -1)
410     log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
411
412   if (pipe (rp) == -1)
413     {
414       err = gpg_error_from_syserror ();
415       log_error (_("error creating a pipe: %s\n"), strerror (errno));
416       return err;
417     }
418
419 #ifdef USE_GNU_PTH      
420   *pid = pth_fork? pth_fork () : fork ();
421 #else
422   *pid = fork ();
423 #endif
424   if (*pid == (pid_t)(-1))
425     {
426       err = gpg_error_from_syserror ();
427       log_error (_("error forking process: %s\n"), strerror (errno));
428       close (rp[0]);
429       close (rp[1]);
430       return err;
431     }
432
433   if (!*pid)
434     { 
435       gcry_control (GCRYCTL_TERM_SECMEM);
436       /* Run child. */
437       do_exec (pgmname, argv, fd, fdout, rp[1], preexec);
438       /*NOTREACHED*/
439     }
440
441   /* Parent. */
442   close (rp[1]);
443
444   *statusfile = fdopen (rp[0], "r");
445   if (!*statusfile)
446     {
447       err = gpg_error_from_syserror ();
448       log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
449       kill (*pid, SIGTERM);
450       *pid = (pid_t)(-1);
451       return err;
452     }
453
454   return 0;
455 #endif /* !HAVE_W32_SYSTEM */
456 }
457
458
459
460 /* Simplified version of gnupg_spawn_process.  This function forks and
461    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
462    and ERRFD to stderr (any of them may be -1 to connect them to
463    /dev/null).  The arguments for the process are expected in the NULL
464    terminated array ARGV.  The program name itself should not be
465    included there.  Calling gnupg_wait_process is required.
466
467    Returns 0 on success or an error code. */
468 gpg_error_t
469 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
470                         int infd, int outfd, int errfd, pid_t *pid)
471 {
472 #ifdef HAVE_W32_SYSTEM
473   gpg_error_t err;
474   SECURITY_ATTRIBUTES sec_attr;
475   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
476   STARTUPINFO si;
477   char *cmdline;
478   int i;
479   HANDLE stdhd[3];
480
481   /* Setup return values.  */
482   *pid = (pid_t)(-1);
483
484   /* Prepare security attributes.  */
485   memset (&sec_attr, 0, sizeof sec_attr );
486   sec_attr.nLength = sizeof sec_attr;
487   sec_attr.bInheritHandle = FALSE;
488   
489   /* Build the command line.  */
490   err = build_w32_commandline (pgmname, argv, &cmdline);
491   if (err)
492     return err; 
493
494   memset (&si, 0, sizeof si);
495   si.cb = sizeof (si);
496   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
497   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
498   stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
499   stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
500   stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
501   si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
502   si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
503   si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
504
505   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline);
506   if (!CreateProcess (pgmname,       /* Program to start.  */
507                       cmdline,       /* Command line arguments.  */
508                       &sec_attr,     /* Process security attributes.  */
509                       &sec_attr,     /* Thread security attributes.  */
510                       TRUE,          /* Inherit handles.  */
511                       (CREATE_DEFAULT_ERROR_MODE
512                        | GetPriorityClass (GetCurrentProcess ())
513                        | CREATE_SUSPENDED),
514                       NULL,          /* Environment.  */
515                       NULL,          /* Use current drive/directory.  */
516                       &si,           /* Startup information. */
517                       &pi            /* Returns process information.  */
518                       ))
519     {
520       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
521       err = gpg_error (GPG_ERR_GENERAL);
522     }
523   else
524     err = 0;
525   xfree (cmdline);
526   for (i=0; i < 3; i++)
527     if (stdhd[i] != INVALID_HANDLE_VALUE)
528       CloseHandle (stdhd[i]);
529   if (err)
530     return err;
531
532   log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
533              " dwProcessID=%d dwThreadId=%d\n",
534              pi.hProcess, pi.hThread,
535              (int) pi.dwProcessId, (int) pi.dwThreadId);
536
537   /* Process has been created suspended; resume it now. */
538   ResumeThread (pi.hThread);
539   CloseHandle (pi.hThread); 
540
541   *pid = handle_to_pid (pi.hProcess);
542   return 0;
543
544 #else /* !HAVE_W32_SYSTEM */
545   gpg_error_t err;
546
547 #ifdef USE_GNU_PTH      
548   *pid = pth_fork? pth_fork () : fork ();
549 #else
550   *pid = fork ();
551 #endif
552   if (*pid == (pid_t)(-1))
553     {
554       err = gpg_error_from_syserror ();
555       log_error (_("error forking process: %s\n"), strerror (errno));
556       return err;
557     }
558
559   if (!*pid)
560     { 
561       gcry_control (GCRYCTL_TERM_SECMEM);
562       /* Run child. */
563       do_exec (pgmname, argv, infd, outfd, errfd, NULL);
564       /*NOTREACHED*/
565     }
566
567   return 0;
568 #endif /* !HAVE_W32_SYSTEM */
569 }
570
571
572 /* Wait for the process identified by PID to terminate. PGMNAME should
573    be the same as supplied to the spawn function and is only used for
574    diagnostics. Returns 0 if the process succeeded, GPG_ERR_GENERAL
575    for any failures of the spawned program or other error codes.  If
576    EXITCODE is not NULL the exit code of the process is stored at this
577    address or -1 if it could not be retrieved. */
578 gpg_error_t
579 gnupg_wait_process (const char *pgmname, pid_t pid, int *exitcode)
580 {
581   gpg_err_code_t ec;
582
583 #ifdef HAVE_W32_SYSTEM
584   HANDLE proc = fd_to_handle (pid);
585   int code;
586   DWORD exc;
587
588   if (exitcode)
589     *exitcode = -1;
590
591   if (pid == (pid_t)(-1))
592     return gpg_error (GPG_ERR_INV_VALUE);
593
594   /* FIXME: We should do a pth_waitpid here.  However this has not yet
595      been implemented.  A special W32 pth system call would even be
596      better.  */
597   code = WaitForSingleObject (proc, INFINITE);
598   switch (code) 
599     {
600       case WAIT_FAILED:
601         log_error (_("waiting for process %d to terminate failed: %s\n"),
602                    (int)pid, w32_strerror (-1));
603         ec = GPG_ERR_GENERAL;
604         break;
605
606       case WAIT_OBJECT_0:
607         if (!GetExitCodeProcess (proc, &exc))
608           {
609             log_error (_("error getting exit code of process %d: %s\n"),
610                          (int)pid, w32_strerror (-1) );
611             ec = GPG_ERR_GENERAL;
612           }
613         else if (exc)
614           {
615             log_error (_("error running `%s': exit status %d\n"),
616                        pgmname, (int)exc );
617             if (exitcode)
618               *exitcode = (int)exc;
619             ec = GPG_ERR_GENERAL;
620           }
621         else
622           {
623             if (exitcode)
624               *exitcode = 0;
625             ec = 0;
626           }
627         CloseHandle (proc);
628         break;
629
630       default:
631         log_error ("WaitForSingleObject returned unexpected "
632                    "code %d for pid %d\n", code, (int)pid );
633         ec = GPG_ERR_GENERAL;
634         break;
635     }
636
637 #else /* !HAVE_W32_SYSTEM */
638   int i, status;
639
640   if (exitcode)
641     *exitcode = -1;
642
643   if (pid == (pid_t)(-1))
644     return gpg_error (GPG_ERR_INV_VALUE);
645
646 #ifdef USE_GNU_PTH
647   i = pth_waitpid ? pth_waitpid (pid, &status, 0) : waitpid (pid, &status, 0);
648 #else
649   while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
650     ;
651 #endif
652   if (i == (pid_t)(-1))
653     {
654       log_error (_("waiting for process %d to terminate failed: %s\n"),
655                  (int)pid, strerror (errno));
656       ec = gpg_err_code_from_errno (errno);
657     }
658   else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
659     {
660       log_error (_("error running `%s': probably not installed\n"), pgmname);
661       ec = GPG_ERR_CONFIGURATION;
662     }
663   else if (WIFEXITED (status) && WEXITSTATUS (status))
664     {
665       log_error (_("error running `%s': exit status %d\n"), pgmname,
666                  WEXITSTATUS (status));
667       if (exitcode)
668         *exitcode = WEXITSTATUS (status);
669       ec = GPG_ERR_GENERAL;
670     }
671   else if (!WIFEXITED (status))
672     {
673       log_error (_("error running `%s': terminated\n"), pgmname);
674       ec = GPG_ERR_GENERAL;
675     }
676   else 
677     {
678       if (exitcode)
679         *exitcode = 0;
680       ec = 0;
681     }
682 #endif /* !HAVE_W32_SYSTEM */
683
684   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
685 }
686
687
688 /* Spawn a new process and immediatley detach from it.  The name of
689    the program to exec is PGMNAME and its arguments are in ARGV (the
690    programname is automatically passed as first argument).
691    Environment strings in ENVP are set.  An error is returned if
692    pgmname is not executable; to make this work it is necessary to
693    provide an absolute file name.  All standard file descriptors are
694    connected to /dev/null. */
695 gpg_error_t
696 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
697                               const char *envp[] )
698 {
699 #ifdef HAVE_W32_SYSTEM
700   gpg_error_t err;
701   SECURITY_ATTRIBUTES sec_attr;
702   PROCESS_INFORMATION pi = 
703     {
704       NULL,      /* Returns process handle.  */
705       0,         /* Returns primary thread handle.  */
706       0,         /* Returns pid.  */
707       0          /* Returns tid.  */
708     };
709   STARTUPINFO si;
710   int cr_flags;
711   char *cmdline;
712
713
714   /* FIXME: We don't make use of ENVP yet.  It is currently only used
715      to pass the GPG_AGENT_INFO variable to gpg-agent.  As the default
716      on windows is to use a standard socket, this does not really
717      matter.  */
718
719
720   if (access (pgmname, X_OK))
721     return gpg_error_from_syserror ();
722
723   /* Prepare security attributes.  */
724   memset (&sec_attr, 0, sizeof sec_attr );
725   sec_attr.nLength = sizeof sec_attr;
726   sec_attr.bInheritHandle = FALSE;
727   
728   /* Build the command line.  */
729   err = build_w32_commandline (pgmname, argv, &cmdline);
730   if (err)
731     return err; 
732
733   /* Start the process.  */
734   memset (&si, 0, sizeof si);
735   si.cb = sizeof (si);
736   si.dwFlags = STARTF_USESHOWWINDOW;
737   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
738
739   cr_flags = (CREATE_DEFAULT_ERROR_MODE
740               | GetPriorityClass (GetCurrentProcess ())
741               | CREATE_NEW_PROCESS_GROUP
742               | DETACHED_PROCESS); 
743   log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n",
744              pgmname, cmdline);
745   if (!CreateProcess (pgmname,       /* Program to start.  */
746                       cmdline,       /* Command line arguments.  */
747                       &sec_attr,     /* Process security attributes.  */
748                       &sec_attr,     /* Thread security attributes.  */
749                       FALSE,         /* Inherit handles.  */
750                       cr_flags,      /* Creation flags.  */
751                       NULL,          /* Environment.  */
752                       NULL,          /* Use current drive/directory.  */
753                       &si,           /* Startup information. */
754                       &pi            /* Returns process information.  */
755                       ))
756     {
757       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
758       xfree (cmdline);
759       return gpg_error (GPG_ERR_GENERAL);
760     }
761   xfree (cmdline);
762   cmdline = NULL;
763
764   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
765              " dwProcessID=%d dwThreadId=%d\n",
766              pi.hProcess, pi.hThread,
767              (int) pi.dwProcessId, (int) pi.dwThreadId);
768
769   CloseHandle (pi.hThread); 
770
771   return 0;
772
773 #else
774   pid_t pid;
775   int i;
776
777   if (getuid() != geteuid())
778     return gpg_error (GPG_ERR_BUG);
779
780   if (access (pgmname, X_OK))
781     return gpg_error_from_syserror ();
782
783 #ifdef USE_GNU_PTH      
784   pid = pth_fork? pth_fork () : fork ();
785 #else
786   pid = fork ();
787 #endif
788   if (pid == (pid_t)(-1))
789     {
790       log_error (_("error forking process: %s\n"), strerror (errno));
791       return gpg_error_from_syserror ();
792     }
793   if (!pid)
794     {
795       gcry_control (GCRYCTL_TERM_SECMEM);
796       if (setsid() == -1 || chdir ("/"))
797         _exit (1);
798       pid = fork (); /* Double fork to let init takes over the new child. */
799       if (pid == (pid_t)(-1))
800         _exit (1);
801       if (pid)
802         _exit (0);  /* Let the parent exit immediately. */
803
804       if (envp)
805         for (i=0; envp[i]; i++)
806           putenv (xstrdup (envp[i]));
807       
808       do_exec (pgmname, argv, -1, -1, -1, NULL);
809
810       /*NOTREACHED*/
811     }
812   
813   if (waitpid (pid, NULL, 0) == -1)
814     log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
815                strerror (errno));
816
817   return 0;
818 #endif /* !HAVE_W32_SYSTEM*/
819 }