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