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