gpgconf: Fix for --homedir.
[gnupg.git] / common / exechelp-w32.c
1 /* exechelp-w32.c - Fork and exec helpers for W32.
2  * Copyright (C) 2004, 2007, 2008, 2009,
3  *               2010 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * This file is free software; you can redistribute it and/or modify
8  * it under the terms of either
9  *
10  *   - the GNU Lesser General Public License as published by the Free
11  *     Software Foundation; either version 3 of the License, or (at
12  *     your option) any later version.
13  *
14  * or
15  *
16  *   - the GNU General Public License as published by the Free
17  *     Software Foundation; either version 2 of the License, or (at
18  *     your option) any later version.
19  *
20  * or both in parallel, as here.
21  *
22  * This file is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, see <http://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32
33 #if !defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM)
34 #error This code is only used on W32.
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <assert.h>
42 #ifdef HAVE_SIGNAL_H
43 # include <signal.h>
44 #endif
45 #include <unistd.h>
46 #include <fcntl.h>
47
48 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth.  */
49 #undef HAVE_NPTH
50 #undef USE_NPTH
51 #endif
52
53 #ifdef HAVE_NPTH
54 #include <npth.h>
55 #endif
56
57 #ifdef HAVE_STAT
58 # include <sys/stat.h>
59 #endif
60
61
62 #include "util.h"
63 #include "i18n.h"
64 #include "sysutils.h"
65 #include "exechelp.h"
66
67 /* Define to 1 do enable debugging.  */
68 #define DEBUG_W32_SPAWN 0
69
70
71 /* It seems Vista doesn't grok X_OK and so fails access() tests.
72    Previous versions interpreted X_OK as F_OK anyway, so we'll just
73    use F_OK directly. */
74 #undef X_OK
75 #define X_OK F_OK
76
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
86
87 /* Return the maximum number of currently allowed open file
88    descriptors.  Only useful on POSIX systems but returns a value on
89    other systems too.  */
90 int
91 get_max_fds (void)
92 {
93   int max_fds = -1;
94
95 #ifdef OPEN_MAX
96   if (max_fds == -1)
97     max_fds = OPEN_MAX;
98 #endif
99
100   if (max_fds == -1)
101     max_fds = 256;  /* Arbitrary limit.  */
102
103   return max_fds;
104 }
105
106
107 /* Under Windows this is a dummy function.  */
108 void
109 close_all_fds (int first, int *except)
110 {
111   (void)first;
112   (void)except;
113 }
114
115
116 /* Returns an array with all currently open file descriptors.  The end
117    of the array is marked by -1.  The caller needs to release this
118    array using the *standard free* and not with xfree.  This allow the
119    use of this function right at startup even before libgcrypt has
120    been initialized.  Returns NULL on error and sets ERRNO
121    accordingly.  */
122 int *
123 get_all_open_fds (void)
124 {
125   int *array;
126   size_t narray;
127   int fd, max_fd, idx;
128 #ifndef HAVE_STAT
129   array = calloc (1, sizeof *array);
130   if (array)
131     array[0] = -1;
132 #else /*HAVE_STAT*/
133   struct stat statbuf;
134
135   max_fd = get_max_fds ();
136   narray = 32;  /* If you change this change also t-exechelp.c.  */
137   array = calloc (narray, sizeof *array);
138   if (!array)
139     return NULL;
140
141   /* Note:  The list we return is ordered.  */
142   for (idx=0, fd=0; fd < max_fd; fd++)
143     if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
144       {
145         if (idx+1 >= narray)
146           {
147             int *tmp;
148
149             narray += (narray < 256)? 32:256;
150             tmp = realloc (array, narray * sizeof *array);
151             if (!tmp)
152               {
153                 free (array);
154                 return NULL;
155               }
156             array = tmp;
157           }
158         array[idx++] = fd;
159       }
160   array[idx] = -1;
161 #endif /*HAVE_STAT*/
162   return array;
163 }
164
165
166 /* Helper function to build_w32_commandline. */
167 static char *
168 build_w32_commandline_copy (char *buffer, const char *string)
169 {
170   char *p = buffer;
171   const char *s;
172
173   if (!*string) /* Empty string. */
174     p = stpcpy (p, "\"\"");
175   else if (strpbrk (string, " \t\n\v\f\""))
176     {
177       /* Need to do some kind of quoting.  */
178       p = stpcpy (p, "\"");
179       for (s=string; *s; s++)
180         {
181           *p++ = *s;
182           if (*s == '\"')
183             *p++ = *s;
184         }
185       *p++ = '\"';
186       *p = 0;
187     }
188   else
189     p = stpcpy (p, string);
190
191   return p;
192 }
193
194 /* Build a command line for use with W32's CreateProcess.  On success
195    CMDLINE gets the address of a newly allocated string.  */
196 static gpg_error_t
197 build_w32_commandline (const char *pgmname, const char * const *argv,
198                        char **cmdline)
199 {
200   int i, n;
201   const char *s;
202   char *buf, *p;
203
204   *cmdline = NULL;
205   n = 0;
206   s = pgmname;
207   n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
208   for (; *s; s++)
209     if (*s == '\"')
210       n++;  /* Need to double inner quotes.  */
211   for (i=0; (s=argv[i]); i++)
212     {
213       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
214       for (; *s; s++)
215         if (*s == '\"')
216           n++;  /* Need to double inner quotes.  */
217     }
218   n++;
219
220   buf = p = xtrymalloc (n);
221   if (!buf)
222     return gpg_error_from_syserror ();
223
224   p = build_w32_commandline_copy (p, pgmname);
225   for (i=0; argv[i]; i++)
226     {
227       *p++ = ' ';
228       p = build_w32_commandline_copy (p, argv[i]);
229     }
230
231   *cmdline= buf;
232   return 0;
233 }
234
235
236 #define INHERIT_READ    1
237 #define INHERIT_WRITE   2
238 #define INHERIT_BOTH    (INHERIT_READ|INHERIT_WRITE)
239
240 /* Create pipe.  FLAGS indicates which ends are inheritable.  */
241 static int
242 create_inheritable_pipe (HANDLE filedes[2], int flags)
243 {
244   HANDLE r, w;
245   SECURITY_ATTRIBUTES sec_attr;
246
247   memset (&sec_attr, 0, sizeof sec_attr );
248   sec_attr.nLength = sizeof sec_attr;
249   sec_attr.bInheritHandle = TRUE;
250
251   if (!CreatePipe (&r, &w, &sec_attr, 0))
252     return -1;
253
254   if ((flags & INHERIT_READ) == 0)
255     if (! SetHandleInformation (r, HANDLE_FLAG_INHERIT, 0))
256       goto fail;
257
258   if ((flags & INHERIT_WRITE) == 0)
259     if (! SetHandleInformation (w, HANDLE_FLAG_INHERIT, 0))
260       goto fail;
261
262   filedes[0] = r;
263   filedes[1] = w;
264   return 0;
265
266  fail:
267   log_error ("SetHandleInformation failed: %s\n", w32_strerror (-1));
268   CloseHandle (r);
269   CloseHandle (w);
270   return -1;
271 }
272
273
274 static HANDLE
275 w32_open_null (int for_write)
276 {
277   HANDLE hfile;
278
279   hfile = CreateFileW (L"nul",
280                        for_write? GENERIC_WRITE : GENERIC_READ,
281                        FILE_SHARE_READ | FILE_SHARE_WRITE,
282                        NULL, OPEN_EXISTING, 0, NULL);
283   if (hfile == INVALID_HANDLE_VALUE)
284     log_debug ("can't open 'nul': %s\n", w32_strerror (-1));
285   return hfile;
286 }
287
288
289 static gpg_error_t
290 do_create_pipe (int filedes[2], int flags)
291 {
292   gpg_error_t err = 0;
293   HANDLE fds[2];
294
295   filedes[0] = filedes[1] = -1;
296   err = gpg_error (GPG_ERR_GENERAL);
297   if (!create_inheritable_pipe (fds, flags))
298     {
299       filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY);
300       if (filedes[0] == -1)
301         {
302           log_error ("failed to translate osfhandle %p\n", fds[0]);
303           CloseHandle (fds[1]);
304         }
305       else
306         {
307           filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), O_APPEND);
308           if (filedes[1] == -1)
309             {
310               log_error ("failed to translate osfhandle %p\n", fds[1]);
311               close (filedes[0]);
312               filedes[0] = -1;
313               CloseHandle (fds[1]);
314             }
315           else
316             err = 0;
317         }
318     }
319   return err;
320 }
321
322 /* Portable function to create a pipe.  Under Windows the write end is
323    inheritable.  If R_FP is not NULL, an estream is created for the
324    read end and stored at R_FP.  */
325 gpg_error_t
326 gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
327 {
328   if (r_fp)
329     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
330   else
331     return do_create_pipe (filedes, INHERIT_WRITE);
332 }
333
334
335 /* Portable function to create a pipe.  Under Windows the read end is
336    inheritable.  If R_FP is not NULL, an estream is created for the
337    write end and stored at R_FP.  */
338 gpg_error_t
339 gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
340 {
341   if (r_fp)
342     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
343   else
344     return do_create_pipe (filedes, INHERIT_READ);
345 }
346
347
348 /* Portable function to create a pipe.  Under Windows both ends are
349    inheritable.  */
350 gpg_error_t
351 gnupg_create_pipe (int filedes[2])
352 {
353   return do_create_pipe (filedes, INHERIT_BOTH);
354 }
355
356
357 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
358 gpg_error_t
359 gnupg_spawn_process (const char *pgmname, const char *argv[],
360                      int *except, void (*preexec)(void), unsigned int flags,
361                      estream_t *r_infp,
362                      estream_t *r_outfp,
363                      estream_t *r_errfp,
364                      pid_t *pid)
365 {
366   gpg_error_t err;
367   SECURITY_ATTRIBUTES sec_attr;
368   PROCESS_INFORMATION pi =
369     {
370       NULL,      /* Returns process handle.  */
371       0,         /* Returns primary thread handle.  */
372       0,         /* Returns pid.  */
373       0          /* Returns tid.  */
374     };
375   STARTUPINFO si;
376   int cr_flags;
377   char *cmdline;
378   HANDLE inpipe[2]  = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
379   HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
380   HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
381   estream_t infp = NULL;
382   estream_t outfp = NULL;
383   estream_t errfp = NULL;
384   HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
385                       INVALID_HANDLE_VALUE,
386                       INVALID_HANDLE_VALUE};
387   int i;
388   es_syshd_t syshd;
389   gpg_err_source_t errsource = default_errsource;
390
391   (void)except; /* Not yet used.  */
392
393   if (r_infp)
394     *r_infp = NULL;
395   if (r_outfp)
396     *r_outfp = NULL;
397   if (r_errfp)
398     *r_errfp = NULL;
399   *pid = (pid_t)(-1); /* Always required.  */
400
401   if (r_infp)
402     {
403       if (create_inheritable_pipe (inpipe, INHERIT_READ))
404         {
405           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
406           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
407           return err;
408         }
409
410       syshd.type = ES_SYSHD_HANDLE;
411       syshd.u.handle = inpipe[1];
412       infp = es_sysopen (&syshd, "w");
413       if (!infp)
414         {
415           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
416           log_error (_("error creating a stream for a pipe: %s\n"),
417                      gpg_strerror (err));
418           CloseHandle (inpipe[0]);
419           CloseHandle (inpipe[1]);
420           inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE;
421           return err;
422         }
423     }
424
425   if (r_outfp)
426     {
427       if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
428         {
429           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
430           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
431           return err;
432         }
433
434       syshd.type = ES_SYSHD_HANDLE;
435       syshd.u.handle = outpipe[0];
436       outfp = es_sysopen (&syshd, "r");
437       if (!outfp)
438         {
439           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
440           log_error (_("error creating a stream for a pipe: %s\n"),
441                      gpg_strerror (err));
442           CloseHandle (outpipe[0]);
443           CloseHandle (outpipe[1]);
444           outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
445           if (infp)
446             es_fclose (infp);
447           else if (inpipe[1] != INVALID_HANDLE_VALUE)
448             CloseHandle (inpipe[1]);
449           if (inpipe[0] != INVALID_HANDLE_VALUE)
450             CloseHandle (inpipe[0]);
451           return err;
452         }
453     }
454
455   if (r_errfp)
456     {
457       if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
458         {
459           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
460           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
461           return err;
462         }
463
464       syshd.type = ES_SYSHD_HANDLE;
465       syshd.u.handle = errpipe[0];
466       errfp = es_sysopen (&syshd, "r");
467       if (!errfp)
468         {
469           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
470           log_error (_("error creating a stream for a pipe: %s\n"),
471                      gpg_strerror (err));
472           CloseHandle (errpipe[0]);
473           CloseHandle (errpipe[1]);
474           errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
475           if (outfp)
476             es_fclose (outfp);
477           else if (outpipe[0] != INVALID_HANDLE_VALUE)
478             CloseHandle (outpipe[0]);
479           if (outpipe[1] != INVALID_HANDLE_VALUE)
480             CloseHandle (outpipe[1]);
481           if (infp)
482             es_fclose (infp);
483           else if (inpipe[1] != INVALID_HANDLE_VALUE)
484             CloseHandle (inpipe[1]);
485           if (inpipe[0] != INVALID_HANDLE_VALUE)
486             CloseHandle (inpipe[0]);
487           return err;
488         }
489     }
490
491   /* Prepare security attributes.  */
492   memset (&sec_attr, 0, sizeof sec_attr );
493   sec_attr.nLength = sizeof sec_attr;
494   sec_attr.bInheritHandle = FALSE;
495
496   /* Build the command line.  */
497   err = build_w32_commandline (pgmname, argv, &cmdline);
498   if (err)
499     return err;
500
501   if (inpipe[0] == INVALID_HANDLE_VALUE)
502     nullhd[0] = w32_open_null (0);
503   if (outpipe[1] == INVALID_HANDLE_VALUE)
504     nullhd[1] = w32_open_null (1);
505   if (errpipe[1] == INVALID_HANDLE_VALUE)
506     nullhd[2] = w32_open_null (1);
507
508   /* Start the process.  Note that we can't run the PREEXEC function
509      because this might change our own environment. */
510   (void)preexec;
511
512   memset (&si, 0, sizeof si);
513   si.cb = sizeof (si);
514   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
515   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
516   si.hStdInput  = inpipe[0]  == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
517   si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
518   si.hStdError  = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
519
520   cr_flags = (CREATE_DEFAULT_ERROR_MODE
521               | ((flags & GNUPG_SPAWN_DETACHED)? DETACHED_PROCESS : 0)
522               | GetPriorityClass (GetCurrentProcess ())
523               | CREATE_SUSPENDED);
524 /*   log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
525   if (!CreateProcess (pgmname,       /* Program to start.  */
526                       cmdline,       /* Command line arguments.  */
527                       &sec_attr,     /* Process security attributes.  */
528                       &sec_attr,     /* Thread security attributes.  */
529                       TRUE,          /* Inherit handles.  */
530                       cr_flags,      /* Creation flags.  */
531                       NULL,          /* Environment.  */
532                       NULL,          /* Use current drive/directory.  */
533                       &si,           /* Startup information. */
534                       &pi            /* Returns process information.  */
535                       ))
536     {
537       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
538       xfree (cmdline);
539       if (infp)
540         es_fclose (infp);
541       else if (inpipe[1] != INVALID_HANDLE_VALUE)
542         CloseHandle (outpipe[1]);
543       if (inpipe[0] != INVALID_HANDLE_VALUE)
544         CloseHandle (inpipe[0]);
545       if (outfp)
546         es_fclose (outfp);
547       else if (outpipe[0] != INVALID_HANDLE_VALUE)
548         CloseHandle (outpipe[0]);
549       if (outpipe[1] != INVALID_HANDLE_VALUE)
550         CloseHandle (outpipe[1]);
551       if (errfp)
552         es_fclose (errfp);
553       else if (errpipe[0] != INVALID_HANDLE_VALUE)
554         CloseHandle (errpipe[0]);
555       if (errpipe[1] != INVALID_HANDLE_VALUE)
556         CloseHandle (errpipe[1]);
557       return gpg_err_make (errsource, GPG_ERR_GENERAL);
558     }
559   xfree (cmdline);
560   cmdline = NULL;
561
562   /* Close the inherited handles to /dev/null.  */
563   for (i=0; i < DIM (nullhd); i++)
564     if (nullhd[i] != INVALID_HANDLE_VALUE)
565       CloseHandle (nullhd[i]);
566
567   /* Close the inherited ends of the pipes.  */
568   if (inpipe[0] != INVALID_HANDLE_VALUE)
569     CloseHandle (inpipe[0]);
570   if (outpipe[1] != INVALID_HANDLE_VALUE)
571     CloseHandle (outpipe[1]);
572   if (errpipe[1] != INVALID_HANDLE_VALUE)
573     CloseHandle (errpipe[1]);
574
575   /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
576   /*            " dwProcessID=%d dwThreadId=%d\n", */
577   /*            pi.hProcess, pi.hThread, */
578   /*            (int) pi.dwProcessId, (int) pi.dwThreadId); */
579   /* log_debug ("                     outfp=%p errfp=%p\n", outfp, errfp); */
580
581   /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
582      invalid argument error if we pass it the correct processID.  As a
583      workaround we use -1 (ASFW_ANY).  */
584   if ((flags & GNUPG_SPAWN_RUN_ASFW))
585     gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
586
587   /* Process has been created suspended; resume it now. */
588   ResumeThread (pi.hThread);
589   CloseHandle (pi.hThread);
590
591   if (r_infp)
592     *r_infp = infp;
593   if (r_outfp)
594     *r_outfp = outfp;
595   if (r_errfp)
596     *r_errfp = errfp;
597
598   *pid = handle_to_pid (pi.hProcess);
599   return 0;
600
601 }
602
603
604
605 /* Simplified version of gnupg_spawn_process.  This function forks and
606    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
607    and ERRFD to stderr (any of them may be -1 to connect them to
608    /dev/null).  The arguments for the process are expected in the NULL
609    terminated array ARGV.  The program name itself should not be
610    included there.  Calling gnupg_wait_process is required.
611
612    Returns 0 on success or an error code. */
613 gpg_error_t
614 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
615                         int infd, int outfd, int errfd, pid_t *pid)
616 {
617   gpg_error_t err;
618   SECURITY_ATTRIBUTES sec_attr;
619   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
620   STARTUPINFO si;
621   char *cmdline;
622   int i;
623   HANDLE stdhd[3];
624
625   /* Setup return values.  */
626   *pid = (pid_t)(-1);
627
628   /* Prepare security attributes.  */
629   memset (&sec_attr, 0, sizeof sec_attr );
630   sec_attr.nLength = sizeof sec_attr;
631   sec_attr.bInheritHandle = FALSE;
632
633   /* Build the command line.  */
634   err = build_w32_commandline (pgmname, argv, &cmdline);
635   if (err)
636     return err;
637
638   memset (&si, 0, sizeof si);
639   si.cb = sizeof (si);
640   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
641   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
642   stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
643   stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
644   stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
645   si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
646   si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
647   si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
648
649 /*   log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
650   if (!CreateProcess (pgmname,       /* Program to start.  */
651                       cmdline,       /* Command line arguments.  */
652                       &sec_attr,     /* Process security attributes.  */
653                       &sec_attr,     /* Thread security attributes.  */
654                       TRUE,          /* Inherit handles.  */
655                       (CREATE_DEFAULT_ERROR_MODE
656                        | GetPriorityClass (GetCurrentProcess ())
657                        | CREATE_SUSPENDED | DETACHED_PROCESS),
658                       NULL,          /* Environment.  */
659                       NULL,          /* Use current drive/directory.  */
660                       &si,           /* Startup information. */
661                       &pi            /* Returns process information.  */
662                       ))
663     {
664       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
665       err = gpg_error (GPG_ERR_GENERAL);
666     }
667   else
668     err = 0;
669   xfree (cmdline);
670   for (i=0; i < 3; i++)
671     if (stdhd[i] != INVALID_HANDLE_VALUE)
672       CloseHandle (stdhd[i]);
673   if (err)
674     return err;
675
676 /*   log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
677 /*              " dwProcessID=%d dwThreadId=%d\n", */
678 /*              pi.hProcess, pi.hThread, */
679 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
680
681   /* Process has been created suspended; resume it now. */
682   ResumeThread (pi.hThread);
683   CloseHandle (pi.hThread);
684
685   *pid = handle_to_pid (pi.hProcess);
686   return 0;
687
688 }
689
690
691 /* See exechelp.h for a description.  */
692 gpg_error_t
693 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
694 {
695   return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
696 }
697
698 /* See exechelp.h for a description.  */
699 gpg_error_t
700 gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
701                       int hang, int *r_exitcodes)
702 {
703   gpg_err_code_t ec = 0;
704   size_t i;
705   HANDLE *procs;
706   int code;
707
708   procs = xtrycalloc (count, sizeof *procs);
709   if (procs == NULL)
710     return gpg_error_from_syserror ();
711
712   for (i = 0; i < count; i++)
713     {
714       if (r_exitcodes)
715         r_exitcodes[i] = -1;
716
717       if (pids[i] == (pid_t)(-1))
718         return gpg_error (GPG_ERR_INV_VALUE);
719
720       procs[i] = fd_to_handle (pids[i]);
721     }
722
723   /* FIXME: We should do a pth_waitpid here.  However this has not yet
724      been implemented.  A special W32 pth system call would even be
725      better.  */
726   code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
727   switch (code)
728     {
729     case WAIT_TIMEOUT:
730       ec = GPG_ERR_TIMEOUT;
731       goto leave;
732
733     case WAIT_FAILED:
734       log_error (_("waiting for processes to terminate failed: %s\n"),
735                  w32_strerror (-1));
736       ec = GPG_ERR_GENERAL;
737       goto leave;
738
739     case WAIT_OBJECT_0:
740       for (i = 0; i < count; i++)
741         {
742           DWORD exc;
743
744           if (! GetExitCodeProcess (procs[i], &exc))
745             {
746               log_error (_("error getting exit code of process %d: %s\n"),
747                          (int) pids[i], w32_strerror (-1) );
748               ec = GPG_ERR_GENERAL;
749             }
750           else if (exc)
751             {
752               if (!r_exitcodes)
753                 log_error (_("error running '%s': exit status %d\n"),
754                            pgmnames[i], (int)exc);
755               else
756                 r_exitcodes[i] = (int)exc;
757               ec = GPG_ERR_GENERAL;
758             }
759           else
760             {
761               if (r_exitcodes)
762                 r_exitcodes[i] = 0;
763             }
764         }
765       break;
766
767     default:
768       log_error ("WaitForMultipleObjects returned unexpected "
769                  "code %d\n", code);
770       ec = GPG_ERR_GENERAL;
771       break;
772     }
773
774  leave:
775   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
776 }
777
778
779
780 void
781 gnupg_release_process (pid_t pid)
782 {
783   if (pid != (pid_t)INVALID_HANDLE_VALUE)
784     {
785       HANDLE process = (HANDLE)pid;
786
787       CloseHandle (process);
788     }
789 }
790
791
792 /* Spawn a new process and immediately detach from it.  The name of
793    the program to exec is PGMNAME and its arguments are in ARGV (the
794    programname is automatically passed as first argument).
795    Environment strings in ENVP are set.  An error is returned if
796    pgmname is not executable; to make this work it is necessary to
797    provide an absolute file name.  All standard file descriptors are
798    connected to /dev/null. */
799 gpg_error_t
800 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
801                               const char *envp[] )
802 {
803   gpg_error_t err;
804   SECURITY_ATTRIBUTES sec_attr;
805   PROCESS_INFORMATION pi =
806     {
807       NULL,      /* Returns process handle.  */
808       0,         /* Returns primary thread handle.  */
809       0,         /* Returns pid.  */
810       0          /* Returns tid.  */
811     };
812   STARTUPINFO si;
813   int cr_flags;
814   char *cmdline;
815
816
817   /* We don't use ENVP.  */
818   (void)envp;
819
820   if (access (pgmname, X_OK))
821     return gpg_error_from_syserror ();
822
823   /* Prepare security attributes.  */
824   memset (&sec_attr, 0, sizeof sec_attr );
825   sec_attr.nLength = sizeof sec_attr;
826   sec_attr.bInheritHandle = FALSE;
827
828   /* Build the command line.  */
829   err = build_w32_commandline (pgmname, argv, &cmdline);
830   if (err)
831     return err;
832
833   /* Start the process.  */
834   memset (&si, 0, sizeof si);
835   si.cb = sizeof (si);
836   si.dwFlags = STARTF_USESHOWWINDOW;
837   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
838
839   cr_flags = (CREATE_DEFAULT_ERROR_MODE
840               | GetPriorityClass (GetCurrentProcess ())
841               | CREATE_NEW_PROCESS_GROUP
842               | DETACHED_PROCESS);
843 /*   log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
844 /*              pgmname, cmdline); */
845   if (!CreateProcess (pgmname,       /* Program to start.  */
846                       cmdline,       /* Command line arguments.  */
847                       &sec_attr,     /* Process security attributes.  */
848                       &sec_attr,     /* Thread security attributes.  */
849                       FALSE,         /* Inherit handles.  */
850                       cr_flags,      /* Creation flags.  */
851                       NULL,          /* Environment.  */
852                       NULL,          /* Use current drive/directory.  */
853                       &si,           /* Startup information. */
854                       &pi            /* Returns process information.  */
855                       ))
856     {
857       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
858       xfree (cmdline);
859       return gpg_error (GPG_ERR_GENERAL);
860     }
861   xfree (cmdline);
862   cmdline = NULL;
863
864 /*   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
865 /*              " dwProcessID=%d dwThreadId=%d\n", */
866 /*              pi.hProcess, pi.hThread, */
867 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
868
869   CloseHandle (pi.hThread);
870   CloseHandle (pi.hProcess);
871
872   return 0;
873 }
874
875
876 /* Kill a process; that is send an appropriate signal to the process.
877    gnupg_wait_process must be called to actually remove the process
878    from the system.  An invalid PID is ignored.  */
879 void
880 gnupg_kill_process (pid_t pid)
881 {
882   if (pid != (pid_t) INVALID_HANDLE_VALUE)
883     {
884       HANDLE process = (HANDLE) pid;
885
886       /* Arbitrary error code.  */
887       TerminateProcess (process, 1);
888     }
889 }