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