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