a8a8b45c58ba002e38d36e97ff2cff8c3e154a71
[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                      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   if (r_infp)
392     *r_infp = NULL;
393   if (r_outfp)
394     *r_outfp = NULL;
395   if (r_errfp)
396     *r_errfp = NULL;
397   *pid = (pid_t)(-1); /* Always required.  */
398
399   if (r_infp)
400     {
401       if (create_inheritable_pipe (inpipe, INHERIT_READ))
402         {
403           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
404           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
405           return err;
406         }
407
408       syshd.type = ES_SYSHD_HANDLE;
409       syshd.u.handle = inpipe[1];
410       infp = es_sysopen (&syshd, "w");
411       if (!infp)
412         {
413           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
414           log_error (_("error creating a stream for a pipe: %s\n"),
415                      gpg_strerror (err));
416           CloseHandle (inpipe[0]);
417           CloseHandle (inpipe[1]);
418           inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE;
419           return err;
420         }
421     }
422
423   if (r_outfp)
424     {
425       if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
426         {
427           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
428           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
429           return err;
430         }
431
432       syshd.type = ES_SYSHD_HANDLE;
433       syshd.u.handle = outpipe[0];
434       outfp = es_sysopen (&syshd, "r");
435       if (!outfp)
436         {
437           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
438           log_error (_("error creating a stream for a pipe: %s\n"),
439                      gpg_strerror (err));
440           CloseHandle (outpipe[0]);
441           CloseHandle (outpipe[1]);
442           outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
443           if (infp)
444             es_fclose (infp);
445           else if (inpipe[1] != INVALID_HANDLE_VALUE)
446             CloseHandle (inpipe[1]);
447           if (inpipe[0] != INVALID_HANDLE_VALUE)
448             CloseHandle (inpipe[0]);
449           return err;
450         }
451     }
452
453   if (r_errfp)
454     {
455       if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
456         {
457           err = gpg_err_make (errsource, GPG_ERR_GENERAL);
458           log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
459           return err;
460         }
461
462       syshd.type = ES_SYSHD_HANDLE;
463       syshd.u.handle = errpipe[0];
464       errfp = es_sysopen (&syshd, "r");
465       if (!errfp)
466         {
467           err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
468           log_error (_("error creating a stream for a pipe: %s\n"),
469                      gpg_strerror (err));
470           CloseHandle (errpipe[0]);
471           CloseHandle (errpipe[1]);
472           errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
473           if (outfp)
474             es_fclose (outfp);
475           else if (outpipe[0] != INVALID_HANDLE_VALUE)
476             CloseHandle (outpipe[0]);
477           if (outpipe[1] != INVALID_HANDLE_VALUE)
478             CloseHandle (outpipe[1]);
479           if (infp)
480             es_fclose (infp);
481           else if (inpipe[1] != INVALID_HANDLE_VALUE)
482             CloseHandle (inpipe[1]);
483           if (inpipe[0] != INVALID_HANDLE_VALUE)
484             CloseHandle (inpipe[0]);
485           return err;
486         }
487     }
488
489   /* Prepare security attributes.  */
490   memset (&sec_attr, 0, sizeof sec_attr );
491   sec_attr.nLength = sizeof sec_attr;
492   sec_attr.bInheritHandle = FALSE;
493
494   /* Build the command line.  */
495   err = build_w32_commandline (pgmname, argv, &cmdline);
496   if (err)
497     return err;
498
499   if (inpipe[0] == INVALID_HANDLE_VALUE)
500     nullhd[0] = w32_open_null (0);
501   if (outpipe[1] == INVALID_HANDLE_VALUE)
502     nullhd[1] = w32_open_null (1);
503   if (errpipe[1] == INVALID_HANDLE_VALUE)
504     nullhd[2] = w32_open_null (1);
505
506   /* Start the process.  Note that we can't run the PREEXEC function
507      because this might change our own environment. */
508   (void)preexec;
509
510   memset (&si, 0, sizeof si);
511   si.cb = sizeof (si);
512   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
513   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
514   si.hStdInput  = inpipe[0]  == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
515   si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
516   si.hStdError  = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
517
518   cr_flags = (CREATE_DEFAULT_ERROR_MODE
519               | ((flags & GNUPG_SPAWN_DETACHED)? DETACHED_PROCESS : 0)
520               | GetPriorityClass (GetCurrentProcess ())
521               | CREATE_SUSPENDED);
522 /*   log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
523   if (!CreateProcess (pgmname,       /* Program to start.  */
524                       cmdline,       /* Command line arguments.  */
525                       &sec_attr,     /* Process security attributes.  */
526                       &sec_attr,     /* Thread security attributes.  */
527                       TRUE,          /* Inherit handles.  */
528                       cr_flags,      /* Creation flags.  */
529                       NULL,          /* Environment.  */
530                       NULL,          /* Use current drive/directory.  */
531                       &si,           /* Startup information. */
532                       &pi            /* Returns process information.  */
533                       ))
534     {
535       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
536       xfree (cmdline);
537       if (infp)
538         es_fclose (infp);
539       else if (inpipe[1] != INVALID_HANDLE_VALUE)
540         CloseHandle (outpipe[1]);
541       if (inpipe[0] != INVALID_HANDLE_VALUE)
542         CloseHandle (inpipe[0]);
543       if (outfp)
544         es_fclose (outfp);
545       else if (outpipe[0] != INVALID_HANDLE_VALUE)
546         CloseHandle (outpipe[0]);
547       if (outpipe[1] != INVALID_HANDLE_VALUE)
548         CloseHandle (outpipe[1]);
549       if (errfp)
550         es_fclose (errfp);
551       else if (errpipe[0] != INVALID_HANDLE_VALUE)
552         CloseHandle (errpipe[0]);
553       if (errpipe[1] != INVALID_HANDLE_VALUE)
554         CloseHandle (errpipe[1]);
555       return gpg_err_make (errsource, GPG_ERR_GENERAL);
556     }
557   xfree (cmdline);
558   cmdline = NULL;
559
560   /* Close the inherited handles to /dev/null.  */
561   for (i=0; i < DIM (nullhd); i++)
562     if (nullhd[i] != INVALID_HANDLE_VALUE)
563       CloseHandle (nullhd[i]);
564
565   /* Close the inherited ends of the pipes.  */
566   if (inpipe[0] != INVALID_HANDLE_VALUE)
567     CloseHandle (inpipe[0]);
568   if (outpipe[1] != INVALID_HANDLE_VALUE)
569     CloseHandle (outpipe[1]);
570   if (errpipe[1] != INVALID_HANDLE_VALUE)
571     CloseHandle (errpipe[1]);
572
573   /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
574   /*            " dwProcessID=%d dwThreadId=%d\n", */
575   /*            pi.hProcess, pi.hThread, */
576   /*            (int) pi.dwProcessId, (int) pi.dwThreadId); */
577   /* log_debug ("                     outfp=%p errfp=%p\n", outfp, errfp); */
578
579   /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
580      invalid argument error if we pass it the correct processID.  As a
581      workaround we use -1 (ASFW_ANY).  */
582   if ((flags & GNUPG_SPAWN_RUN_ASFW))
583     gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
584
585   /* Process has been created suspended; resume it now. */
586   ResumeThread (pi.hThread);
587   CloseHandle (pi.hThread);
588
589   if (r_infp)
590     *r_infp = infp;
591   if (r_outfp)
592     *r_outfp = outfp;
593   if (r_errfp)
594     *r_errfp = errfp;
595
596   *pid = handle_to_pid (pi.hProcess);
597   return 0;
598
599 }
600
601
602
603 /* Simplified version of gnupg_spawn_process.  This function forks and
604    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
605    and ERRFD to stderr (any of them may be -1 to connect them to
606    /dev/null).  The arguments for the process are expected in the NULL
607    terminated array ARGV.  The program name itself should not be
608    included there.  Calling gnupg_wait_process is required.
609
610    Returns 0 on success or an error code. */
611 gpg_error_t
612 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
613                         int infd, int outfd, int errfd, pid_t *pid)
614 {
615   gpg_error_t err;
616   SECURITY_ATTRIBUTES sec_attr;
617   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
618   STARTUPINFO si;
619   char *cmdline;
620   int i;
621   HANDLE stdhd[3];
622
623   /* Setup return values.  */
624   *pid = (pid_t)(-1);
625
626   /* Prepare security attributes.  */
627   memset (&sec_attr, 0, sizeof sec_attr );
628   sec_attr.nLength = sizeof sec_attr;
629   sec_attr.bInheritHandle = FALSE;
630
631   /* Build the command line.  */
632   err = build_w32_commandline (pgmname, argv, &cmdline);
633   if (err)
634     return err;
635
636   memset (&si, 0, sizeof si);
637   si.cb = sizeof (si);
638   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
639   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
640   stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
641   stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
642   stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
643   si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
644   si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
645   si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
646
647 /*   log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
648   if (!CreateProcess (pgmname,       /* Program to start.  */
649                       cmdline,       /* Command line arguments.  */
650                       &sec_attr,     /* Process security attributes.  */
651                       &sec_attr,     /* Thread security attributes.  */
652                       TRUE,          /* Inherit handles.  */
653                       (CREATE_DEFAULT_ERROR_MODE
654                        | GetPriorityClass (GetCurrentProcess ())
655                        | CREATE_SUSPENDED | DETACHED_PROCESS),
656                       NULL,          /* Environment.  */
657                       NULL,          /* Use current drive/directory.  */
658                       &si,           /* Startup information. */
659                       &pi            /* Returns process information.  */
660                       ))
661     {
662       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
663       err = gpg_error (GPG_ERR_GENERAL);
664     }
665   else
666     err = 0;
667   xfree (cmdline);
668   for (i=0; i < 3; i++)
669     if (stdhd[i] != INVALID_HANDLE_VALUE)
670       CloseHandle (stdhd[i]);
671   if (err)
672     return err;
673
674 /*   log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
675 /*              " dwProcessID=%d dwThreadId=%d\n", */
676 /*              pi.hProcess, pi.hThread, */
677 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
678
679   /* Process has been created suspended; resume it now. */
680   ResumeThread (pi.hThread);
681   CloseHandle (pi.hThread);
682
683   *pid = handle_to_pid (pi.hProcess);
684   return 0;
685
686 }
687
688
689 /* See exechelp.h for a description.  */
690 gpg_error_t
691 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
692 {
693   return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
694 }
695
696 /* See exechelp.h for a description.  */
697 gpg_error_t
698 gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
699                       int hang, int *r_exitcodes)
700 {
701   gpg_err_code_t ec = 0;
702   size_t i;
703   HANDLE *procs;
704   int code;
705
706   procs = xtrycalloc (count, sizeof *procs);
707   if (procs == NULL)
708     return gpg_error_from_syserror ();
709
710   for (i = 0; i < count; i++)
711     {
712       if (r_exitcodes)
713         r_exitcodes[i] = -1;
714
715       if (pids[i] == (pid_t)(-1))
716         return gpg_error (GPG_ERR_INV_VALUE);
717
718       procs[i] = fd_to_handle (pids[i]);
719     }
720
721   /* FIXME: We should do a pth_waitpid here.  However this has not yet
722      been implemented.  A special W32 pth system call would even be
723      better.  */
724   code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
725   switch (code)
726     {
727     case WAIT_TIMEOUT:
728       ec = GPG_ERR_TIMEOUT;
729       goto leave;
730
731     case WAIT_FAILED:
732       log_error (_("waiting for processes to terminate failed: %s\n"),
733                  w32_strerror (-1));
734       ec = GPG_ERR_GENERAL;
735       goto leave;
736
737     case WAIT_OBJECT_0:
738       for (i = 0; i < count; i++)
739         {
740           DWORD exc;
741
742           if (! GetExitCodeProcess (procs[i], &exc))
743             {
744               log_error (_("error getting exit code of process %d: %s\n"),
745                          (int) pids[i], w32_strerror (-1) );
746               ec = GPG_ERR_GENERAL;
747             }
748           else if (exc)
749             {
750               if (!r_exitcodes)
751                 log_error (_("error running '%s': exit status %d\n"),
752                            pgmnames[i], (int)exc);
753               else
754                 r_exitcodes[i] = (int)exc;
755               ec = GPG_ERR_GENERAL;
756             }
757           else
758             {
759               if (r_exitcodes)
760                 r_exitcodes[i] = 0;
761             }
762         }
763       break;
764
765     default:
766       log_error ("WaitForMultipleObjects returned unexpected "
767                  "code %d\n", code);
768       ec = GPG_ERR_GENERAL;
769       break;
770     }
771
772  leave:
773   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
774 }
775
776
777
778 void
779 gnupg_release_process (pid_t pid)
780 {
781   if (pid != (pid_t)INVALID_HANDLE_VALUE)
782     {
783       HANDLE process = (HANDLE)pid;
784
785       CloseHandle (process);
786     }
787 }
788
789
790 /* Spawn a new process and immediately detach from it.  The name of
791    the program to exec is PGMNAME and its arguments are in ARGV (the
792    programname is automatically passed as first argument).
793    Environment strings in ENVP are set.  An error is returned if
794    pgmname is not executable; to make this work it is necessary to
795    provide an absolute file name.  All standard file descriptors are
796    connected to /dev/null. */
797 gpg_error_t
798 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
799                               const char *envp[] )
800 {
801   gpg_error_t err;
802   SECURITY_ATTRIBUTES sec_attr;
803   PROCESS_INFORMATION pi =
804     {
805       NULL,      /* Returns process handle.  */
806       0,         /* Returns primary thread handle.  */
807       0,         /* Returns pid.  */
808       0          /* Returns tid.  */
809     };
810   STARTUPINFO si;
811   int cr_flags;
812   char *cmdline;
813
814
815   /* We don't use ENVP.  */
816   (void)envp;
817
818   if (access (pgmname, X_OK))
819     return gpg_error_from_syserror ();
820
821   /* Prepare security attributes.  */
822   memset (&sec_attr, 0, sizeof sec_attr );
823   sec_attr.nLength = sizeof sec_attr;
824   sec_attr.bInheritHandle = FALSE;
825
826   /* Build the command line.  */
827   err = build_w32_commandline (pgmname, argv, &cmdline);
828   if (err)
829     return err;
830
831   /* Start the process.  */
832   memset (&si, 0, sizeof si);
833   si.cb = sizeof (si);
834   si.dwFlags = STARTF_USESHOWWINDOW;
835   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
836
837   cr_flags = (CREATE_DEFAULT_ERROR_MODE
838               | GetPriorityClass (GetCurrentProcess ())
839               | CREATE_NEW_PROCESS_GROUP
840               | DETACHED_PROCESS);
841 /*   log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
842 /*              pgmname, cmdline); */
843   if (!CreateProcess (pgmname,       /* Program to start.  */
844                       cmdline,       /* Command line arguments.  */
845                       &sec_attr,     /* Process security attributes.  */
846                       &sec_attr,     /* Thread security attributes.  */
847                       FALSE,         /* Inherit handles.  */
848                       cr_flags,      /* Creation flags.  */
849                       NULL,          /* Environment.  */
850                       NULL,          /* Use current drive/directory.  */
851                       &si,           /* Startup information. */
852                       &pi            /* Returns process information.  */
853                       ))
854     {
855       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
856       xfree (cmdline);
857       return gpg_error (GPG_ERR_GENERAL);
858     }
859   xfree (cmdline);
860   cmdline = NULL;
861
862 /*   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
863 /*              " dwProcessID=%d dwThreadId=%d\n", */
864 /*              pi.hProcess, pi.hThread, */
865 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
866
867   CloseHandle (pi.hThread);
868   CloseHandle (pi.hProcess);
869
870   return 0;
871 }
872
873
874 /* Kill a process; that is send an appropriate signal to the process.
875    gnupg_wait_process must be called to actually remove the process
876    from the system.  An invalid PID is ignored.  */
877 void
878 gnupg_kill_process (pid_t pid)
879 {
880   if (pid != (pid_t) INVALID_HANDLE_VALUE)
881     {
882       HANDLE process = (HANDLE) pid;
883
884       /* Arbitrary error code.  */
885       TerminateProcess (process, 1);
886     }
887 }