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