Merged Dirmngr with GnuPG.
[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  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #if !defined(HAVE_W32_SYSTEM) || defined (HAVE_W32CE_SYSTEM)
24 #error This code is only used on W32.
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <assert.h>
32 #ifdef HAVE_SIGNAL_H
33 # include <signal.h>
34 #endif
35 #include <unistd.h> 
36 #include <fcntl.h>
37
38 #ifdef WITHOUT_GNU_PTH /* Give the Makefile a chance to build without Pth.  */
39 #undef HAVE_PTH
40 #undef USE_GNU_PTH
41 #endif
42
43 #ifdef USE_GNU_PTH      
44 #include <pth.h>
45 #endif
46
47 #ifdef HAVE_STAT
48 # include <sys/stat.h>
49 #endif
50
51
52 #include "util.h"
53 #include "i18n.h"
54 #include "sysutils.h"
55 #include "exechelp.h"
56
57 /* Define to 1 do enable debugging.  */
58 #define DEBUG_W32_SPAWN 1
59
60
61 /* It seems Vista doesn't grok X_OK and so fails access() tests.
62    Previous versions interpreted X_OK as F_OK anyway, so we'll just
63    use F_OK directly. */
64 #undef X_OK
65 #define X_OK F_OK
66
67 /* We assume that a HANDLE can be represented by an int which should
68    be true for all i386 systems (HANDLE is defined as void *) and
69    these are the only systems for which Windows is available.  Further
70    we assume that -1 denotes an invalid handle.  */
71 # define fd_to_handle(a)  ((HANDLE)(a))
72 # define handle_to_fd(a)  ((int)(a))
73 # define pid_to_handle(a) ((HANDLE)(a))
74 # define handle_to_pid(a) ((int)(a))
75
76
77 /* Return the maximum number of currently allowed open file
78    descriptors.  Only useful on POSIX systems but returns a value on
79    other systems too.  */
80 int
81 get_max_fds (void)
82 {
83   int max_fds = -1;
84
85 #ifdef OPEN_MAX
86   if (max_fds == -1)
87     max_fds = OPEN_MAX;
88 #endif
89
90   if (max_fds == -1)
91     max_fds = 256;  /* Arbitrary limit.  */
92
93   return max_fds;
94 }
95
96
97 /* Close all file descriptors starting with descriptor FIRST.  If
98    EXCEPT is not NULL, it is expected to be a list of file descriptors
99    which shall not be closed.  This list shall be sorted in ascending
100    order with the end marked by -1.  */
101 void
102 close_all_fds (int first, int *except)
103 {
104   int max_fd = get_max_fds ();
105   int fd, i, except_start;
106
107   if (except)
108     {
109       except_start = 0;
110       for (fd=first; fd < max_fd; fd++)
111         {
112           for (i=except_start; except[i] != -1; i++)
113             {
114               if (except[i] == fd)
115                 {
116                   /* If we found the descriptor in the exception list
117                      we can start the next compare run at the next
118                      index because the exception list is ordered.  */
119                 except_start = i + 1;
120                 break;
121                 }
122             }
123           if (except[i] == -1)
124             close (fd);
125         }
126     }
127   else
128     {
129       for (fd=first; fd < max_fd; fd++)
130         close (fd);
131     }
132
133   gpg_err_set_errno (0);
134 }
135
136
137 /* Returns an array with all currently open file descriptors.  The end
138    of the array is marked by -1.  The caller needs to release this
139    array using the *standard free* and not with xfree.  This allow the
140    use of this fucntion right at startup even before libgcrypt has
141    been initialized.  Returns NULL on error and sets ERRNO
142    accordingly.  */
143 int *
144 get_all_open_fds (void)
145 {
146   int *array;
147   size_t narray;
148   int fd, max_fd, idx;
149 #ifndef HAVE_STAT
150   array = calloc (1, sizeof *array);
151   if (array)
152     array[0] = -1;
153 #else /*HAVE_STAT*/
154   struct stat statbuf;
155
156   max_fd = get_max_fds ();
157   narray = 32;  /* If you change this change also t-exechelp.c.  */
158   array = calloc (narray, sizeof *array);
159   if (!array)
160     return NULL;
161   
162   /* Note:  The list we return is ordered.  */
163   for (idx=0, fd=0; fd < max_fd; fd++)
164     if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
165       {
166         if (idx+1 >= narray)
167           {
168             int *tmp;
169
170             narray += (narray < 256)? 32:256;
171             tmp = realloc (array, narray * sizeof *array);
172             if (!tmp)
173               {
174                 free (array);
175                 return NULL;
176               }
177             array = tmp;
178           }
179         array[idx++] = fd;
180       }
181   array[idx] = -1;
182 #endif /*HAVE_STAT*/
183   return array;
184 }
185
186
187 /* Helper function to build_w32_commandline. */
188 static char *
189 build_w32_commandline_copy (char *buffer, const char *string)
190 {
191   char *p = buffer;
192   const char *s;
193
194   if (!*string) /* Empty string. */
195     p = stpcpy (p, "\"\"");
196   else if (strpbrk (string, " \t\n\v\f\""))
197     {
198       /* Need to do some kind of quoting.  */
199       p = stpcpy (p, "\"");
200       for (s=string; *s; s++)
201         {
202           *p++ = *s;
203           if (*s == '\"')
204             *p++ = *s;
205         }
206       *p++ = '\"';
207       *p = 0;
208     }
209   else
210     p = stpcpy (p, string);
211
212   return p;
213 }
214
215 /* Build a command line for use with W32's CreateProcess.  On success
216    CMDLINE gets the address of a newly allocated string.  */
217 static gpg_error_t
218 build_w32_commandline (const char *pgmname, const char * const *argv, 
219                        char **cmdline)
220 {
221   int i, n;
222   const char *s;
223   char *buf, *p;
224
225   *cmdline = NULL;
226   n = 0;
227   s = pgmname;
228   n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
229   for (; *s; s++)
230     if (*s == '\"')
231       n++;  /* Need to double inner quotes.  */
232   for (i=0; (s=argv[i]); i++)
233     {
234       n += strlen (s) + 1 + 2;  /* (1 space, 2 quoting */
235       for (; *s; s++)
236         if (*s == '\"')
237           n++;  /* Need to double inner quotes.  */
238     }
239   n++;
240
241   buf = p = xtrymalloc (n);
242   if (!buf)
243     return gpg_error_from_syserror ();
244
245   p = build_w32_commandline_copy (p, pgmname);
246   for (i=0; argv[i]; i++) 
247     {
248       *p++ = ' ';
249       p = build_w32_commandline_copy (p, argv[i]);
250     }
251
252   *cmdline= buf;
253   return 0;
254 }
255
256
257 /* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
258    the read end is inheritable, with 1 the write end is inheritable.  */
259 static int
260 create_inheritable_pipe (int filedes[2], int inherit_idx)
261 {
262   HANDLE r, w, h;
263   SECURITY_ATTRIBUTES sec_attr;
264
265   memset (&sec_attr, 0, sizeof sec_attr );
266   sec_attr.nLength = sizeof sec_attr;
267   sec_attr.bInheritHandle = FALSE;
268     
269   if (!CreatePipe (&r, &w, &sec_attr, 0))
270     return -1;
271
272   if (!DuplicateHandle (GetCurrentProcess(), inherit_idx? w : r,
273                         GetCurrentProcess(), &h, 0,
274                         TRUE, DUPLICATE_SAME_ACCESS ))
275     {
276       log_error ("DuplicateHandle failed: %s\n", w32_strerror (-1));
277       CloseHandle (r);
278       CloseHandle (w);
279       return -1;
280     }
281
282   if (inherit_idx)
283     {
284       CloseHandle (w);
285       w = h;
286     }
287   else
288     {
289       CloseHandle (r);
290       r = h;
291     }
292
293   filedes[0] = handle_to_fd (r);
294   filedes[1] = handle_to_fd (w);
295   return 0;
296 }
297
298
299 static HANDLE
300 w32_open_null (int for_write)
301 {
302   HANDLE hfile;
303
304   hfile = CreateFileW (L"nul",
305                        for_write? GENERIC_WRITE : GENERIC_READ,
306                        FILE_SHARE_READ | FILE_SHARE_WRITE,
307                        NULL, OPEN_EXISTING, 0, NULL);
308   if (hfile == INVALID_HANDLE_VALUE)
309     log_debug ("can't open `nul': %s\n", w32_strerror (-1));
310   return hfile;
311 }
312
313
314 static gpg_error_t
315 do_create_pipe (int filedes[2], int inherit_idx)
316 {
317   gpg_error_t err = 0;
318   int fds[2];
319
320   filedes[0] = filedes[1] = -1;
321   err = gpg_error (GPG_ERR_GENERAL);
322   if (!create_inheritable_pipe (fds, inherit_idx))
323     {
324       filedes[0] = _open_osfhandle (fds[0], 0);
325       if (filedes[0] == -1)
326         {
327           log_error ("failed to translate osfhandle %p\n", (void*)fds[0]);
328           CloseHandle (fd_to_handle (fds[1]));
329         }
330       else 
331         {
332           filedes[1] = _open_osfhandle (fds[1], 1);
333           if (filedes[1] == -1)
334             {
335               log_error ("failed to translate osfhandle %p\n", (void*)fds[1]);
336               close (filedes[0]);
337               filedes[0] = -1;
338               CloseHandle (fd_to_handle (fds[1]));
339             }
340           else
341             err = 0;
342         }
343     }
344   return err;
345 }
346
347 /* Portable function to create a pipe.  Under Windows the write end is
348    inheritable.  */
349 gpg_error_t
350 gnupg_create_inbound_pipe (int filedes[2])
351 {
352   return do_create_pipe (filedes, 1);
353 }
354
355
356 /* Portable function to create a pipe.  Under Windows the read end is
357    inheritable.  */
358 gpg_error_t
359 gnupg_create_outbound_pipe (int filedes[2])
360 {
361   return do_create_pipe (filedes, 0);
362 }
363
364
365 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
366 gpg_error_t
367 gnupg_spawn_process (const char *pgmname, const char *argv[],
368                      estream_t infile, estream_t outfile,
369                      void (*preexec)(void), unsigned int flags,
370                      estream_t *statusfile, pid_t *pid)
371 {
372   gpg_error_t err;
373   SECURITY_ATTRIBUTES sec_attr;
374   PROCESS_INFORMATION pi = 
375     {
376       NULL,      /* Returns process handle.  */
377       0,         /* Returns primary thread handle.  */
378       0,         /* Returns pid.  */
379       0          /* Returns tid.  */
380     };
381   STARTUPINFO si;
382   int cr_flags;
383   char *cmdline;
384   int fd, fdout, rp[2];
385   HANDLE nullhd[2];
386   int i;
387
388   (void)preexec;
389
390   /* Setup return values.  */
391   *statusfile = NULL;
392   *pid = (pid_t)(-1);
393   
394   if (infile)
395     {
396       es_fflush (infile);
397       es_rewind (infile);
398       fd = _get_osfhandle (es_fileno (infile));
399     }
400   else
401     fd = -1;
402
403   if (outfile)
404     fdout = _get_osfhandle (es_fileno (outfile));
405   else
406     fdout = -1;
407
408   if ( (infile && fd == -1) || (outfile && fdout == -1))
409     log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
410
411   /* Prepare security attributes.  */
412   memset (&sec_attr, 0, sizeof sec_attr );
413   sec_attr.nLength = sizeof sec_attr;
414   sec_attr.bInheritHandle = FALSE;
415   
416   /* Build the command line.  */
417   err = build_w32_commandline (pgmname, argv, &cmdline);
418   if (err)
419     return err; 
420
421   /* Create a pipe.  */
422   if (create_inheritable_pipe (rp, 1))
423     {
424       err = gpg_error (GPG_ERR_GENERAL);
425       log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
426       xfree (cmdline);
427       return err;
428     }
429   
430   nullhd[0] =    fd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
431   nullhd[1] = fdout == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
432
433   /* Start the process.  Note that we can't run the PREEXEC function
434      because this would change our own environment. */
435   memset (&si, 0, sizeof si);
436   si.cb = sizeof (si);
437   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
438   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
439   si.hStdInput  =    fd == -1? nullhd[0] : fd_to_handle (fd);
440   si.hStdOutput = fdout == -1? nullhd[1] : fd_to_handle (fdout);
441   si.hStdError  = fd_to_handle (rp[1]);
442
443   cr_flags = (CREATE_DEFAULT_ERROR_MODE
444               | ((flags & 128)? DETACHED_PROCESS : 0)
445               | GetPriorityClass (GetCurrentProcess ())
446               | CREATE_SUSPENDED); 
447 /*   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
448   if (!CreateProcess (pgmname,       /* Program to start.  */
449                       cmdline,       /* Command line arguments.  */
450                       &sec_attr,     /* Process security attributes.  */
451                       &sec_attr,     /* Thread security attributes.  */
452                       TRUE,          /* Inherit handles.  */
453                       cr_flags,      /* Creation flags.  */
454                       NULL,          /* Environment.  */
455                       NULL,          /* Use current drive/directory.  */
456                       &si,           /* Startup information. */
457                       &pi            /* Returns process information.  */
458                       ))
459     {
460       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
461       xfree (cmdline);
462       CloseHandle (fd_to_handle (rp[0]));
463       CloseHandle (fd_to_handle (rp[1]));
464       return gpg_error (GPG_ERR_GENERAL);
465     }
466   xfree (cmdline);
467   cmdline = NULL;
468
469   /* Close the inherited handles to /dev/null.  */
470   for (i=0; i < DIM (nullhd); i++)
471     if (nullhd[i] != INVALID_HANDLE_VALUE)
472       CloseHandle (nullhd[i]);
473
474   /* Close the other end of the pipe.  */
475   CloseHandle (fd_to_handle (rp[1]));
476   
477 /*   log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
478 /*              " dwProcessID=%d dwThreadId=%d\n", */
479 /*              pi.hProcess, pi.hThread, */
480 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
481   
482   /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
483      invalid argument error if we pass the correct processID to
484      it.  As a workaround we use -1 (ASFW_ANY).  */
485   if ( (flags & 64) )
486     gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
487
488   /* Process has been created suspended; resume it now. */
489   ResumeThread (pi.hThread);
490   CloseHandle (pi.hThread); 
491
492   {
493     int x;
494
495     x = _open_osfhandle (rp[0], 0);
496     if (x == -1)
497       log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
498     else 
499       *statusfile = es_fdopen (x, "r");
500   }
501   if (!*statusfile)
502     {
503       err = gpg_error_from_syserror ();
504       log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
505       CloseHandle (pi.hProcess);
506       return err;
507     }
508
509   *pid = handle_to_pid (pi.hProcess);
510   return 0;
511
512 }
513
514
515
516 /* Simplified version of gnupg_spawn_process.  This function forks and
517    then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
518    and ERRFD to stderr (any of them may be -1 to connect them to
519    /dev/null).  The arguments for the process are expected in the NULL
520    terminated array ARGV.  The program name itself should not be
521    included there.  Calling gnupg_wait_process is required.
522
523    Returns 0 on success or an error code. */
524 gpg_error_t
525 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
526                         int infd, int outfd, int errfd, pid_t *pid)
527 {
528   gpg_error_t err;
529   SECURITY_ATTRIBUTES sec_attr;
530   PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
531   STARTUPINFO si;
532   char *cmdline;
533   int i;
534   HANDLE stdhd[3];
535
536   /* Setup return values.  */
537   *pid = (pid_t)(-1);
538
539   /* Prepare security attributes.  */
540   memset (&sec_attr, 0, sizeof sec_attr );
541   sec_attr.nLength = sizeof sec_attr;
542   sec_attr.bInheritHandle = FALSE;
543   
544   /* Build the command line.  */
545   err = build_w32_commandline (pgmname, argv, &cmdline);
546   if (err)
547     return err; 
548
549   memset (&si, 0, sizeof si);
550   si.cb = sizeof (si);
551   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
552   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
553   stdhd[0] = infd  == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
554   stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
555   stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
556   si.hStdInput  = infd  == -1? stdhd[0] : (void*)_get_osfhandle (infd);
557   si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
558   si.hStdError  = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
559
560 /*   log_debug ("CreateProcess, path=`%s' cmdline=`%s'\n", pgmname, cmdline); */
561   if (!CreateProcess (pgmname,       /* Program to start.  */
562                       cmdline,       /* Command line arguments.  */
563                       &sec_attr,     /* Process security attributes.  */
564                       &sec_attr,     /* Thread security attributes.  */
565                       TRUE,          /* Inherit handles.  */
566                       (CREATE_DEFAULT_ERROR_MODE
567                        | GetPriorityClass (GetCurrentProcess ())
568                        | CREATE_SUSPENDED | DETACHED_PROCESS),
569                       NULL,          /* Environment.  */
570                       NULL,          /* Use current drive/directory.  */
571                       &si,           /* Startup information. */
572                       &pi            /* Returns process information.  */
573                       ))
574     {
575       log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
576       err = gpg_error (GPG_ERR_GENERAL);
577     }
578   else
579     err = 0;
580   xfree (cmdline);
581   for (i=0; i < 3; i++)
582     if (stdhd[i] != INVALID_HANDLE_VALUE)
583       CloseHandle (stdhd[i]);
584   if (err)
585     return err;
586
587 /*   log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
588 /*              " dwProcessID=%d dwThreadId=%d\n", */
589 /*              pi.hProcess, pi.hThread, */
590 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
591
592   /* Process has been created suspended; resume it now. */
593   ResumeThread (pi.hThread);
594   CloseHandle (pi.hThread); 
595
596   *pid = handle_to_pid (pi.hProcess);
597   return 0;
598
599 }
600
601
602 /* See exechelp.h for a description.  */
603 gpg_error_t
604 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
605 {
606   gpg_err_code_t ec;
607   HANDLE proc = fd_to_handle (pid);
608   int code;
609   DWORD exc;
610
611   if (r_exitcode)
612     *r_exitcode = -1;
613
614   if (pid == (pid_t)(-1))
615     return gpg_error (GPG_ERR_INV_VALUE);
616
617   /* FIXME: We should do a pth_waitpid here.  However this has not yet
618      been implemented.  A special W32 pth system call would even be
619      better.  */
620   code = WaitForSingleObject (proc, hang? INFINITE : 0);
621   switch (code) 
622     {
623     case WAIT_TIMEOUT:
624       ec = GPG_ERR_TIMEOUT;
625       break;
626
627     case WAIT_FAILED:
628       log_error (_("waiting for process %d to terminate failed: %s\n"),
629                  (int)pid, w32_strerror (-1));
630       ec = GPG_ERR_GENERAL;
631       break;
632
633     case WAIT_OBJECT_0:
634       if (!GetExitCodeProcess (proc, &exc))
635         {
636           log_error (_("error getting exit code of process %d: %s\n"),
637                      (int)pid, w32_strerror (-1) );
638           ec = GPG_ERR_GENERAL;
639         }
640       else if (exc)
641         {
642           log_error (_("error running `%s': exit status %d\n"),
643                      pgmname, (int)exc );
644           if (r_exitcode)
645             *r_exitcode = (int)exc;
646           ec = GPG_ERR_GENERAL;
647         }
648       else
649         {
650           if (r_exitcode)
651             *r_exitcode = 0;
652           ec = 0;
653         }
654       break;
655       
656     default:
657       log_error ("WaitForSingleObject returned unexpected "
658                  "code %d for pid %d\n", code, (int)pid );
659       ec = GPG_ERR_GENERAL;
660       break;
661     }
662   
663   return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
664 }
665
666
667
668 void
669 gnupg_release_process (pid_t pid)
670 {
671   if (pid != (pid_t)INVALID_HANDLE_VALUE)
672     {
673       HANDLE process = (HANDLE)pid;
674       
675       CloseHandle (process);
676     }
677 }
678
679
680 /* Spawn a new process and immediatley detach from it.  The name of
681    the program to exec is PGMNAME and its arguments are in ARGV (the
682    programname is automatically passed as first argument).
683    Environment strings in ENVP are set.  An error is returned if
684    pgmname is not executable; to make this work it is necessary to
685    provide an absolute file name.  All standard file descriptors are
686    connected to /dev/null. */
687 gpg_error_t
688 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
689                               const char *envp[] )
690 {
691   gpg_error_t err;
692   SECURITY_ATTRIBUTES sec_attr;
693   PROCESS_INFORMATION pi = 
694     {
695       NULL,      /* Returns process handle.  */
696       0,         /* Returns primary thread handle.  */
697       0,         /* Returns pid.  */
698       0          /* Returns tid.  */
699     };
700   STARTUPINFO si;
701   int cr_flags;
702   char *cmdline;
703
704
705   /* FIXME: We don't make use of ENVP yet.  It is currently only used
706      to pass the GPG_AGENT_INFO variable to gpg-agent.  As the default
707      on windows is to use a standard socket, this does not really
708      matter.  */
709   (void)envp;
710
711   if (access (pgmname, X_OK))
712     return gpg_error_from_syserror ();
713
714   /* Prepare security attributes.  */
715   memset (&sec_attr, 0, sizeof sec_attr );
716   sec_attr.nLength = sizeof sec_attr;
717   sec_attr.bInheritHandle = FALSE;
718   
719   /* Build the command line.  */
720   err = build_w32_commandline (pgmname, argv, &cmdline);
721   if (err)
722     return err; 
723
724   /* Start the process.  */
725   memset (&si, 0, sizeof si);
726   si.cb = sizeof (si);
727   si.dwFlags = STARTF_USESHOWWINDOW;
728   si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
729
730   cr_flags = (CREATE_DEFAULT_ERROR_MODE
731               | GetPriorityClass (GetCurrentProcess ())
732               | CREATE_NEW_PROCESS_GROUP
733               | DETACHED_PROCESS); 
734 /*   log_debug ("CreateProcess(detached), path=`%s' cmdline=`%s'\n", */
735 /*              pgmname, cmdline); */
736   if (!CreateProcess (pgmname,       /* Program to start.  */
737                       cmdline,       /* Command line arguments.  */
738                       &sec_attr,     /* Process security attributes.  */
739                       &sec_attr,     /* Thread security attributes.  */
740                       FALSE,         /* Inherit handles.  */
741                       cr_flags,      /* Creation flags.  */
742                       NULL,          /* Environment.  */
743                       NULL,          /* Use current drive/directory.  */
744                       &si,           /* Startup information. */
745                       &pi            /* Returns process information.  */
746                       ))
747     {
748       log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
749       xfree (cmdline);
750       return gpg_error (GPG_ERR_GENERAL);
751     }
752   xfree (cmdline);
753   cmdline = NULL;
754
755 /*   log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
756 /*              " dwProcessID=%d dwThreadId=%d\n", */
757 /*              pi.hProcess, pi.hThread, */
758 /*              (int) pi.dwProcessId, (int) pi.dwThreadId); */
759
760   CloseHandle (pi.hThread); 
761
762   return 0;
763 }
764
765
766 /* Kill a process; that is send an appropriate signal to the process.
767    gnupg_wait_process must be called to actually remove the process
768    from the system.  An invalid PID is ignored.  */
769 void
770 gnupg_kill_process (pid_t pid)
771 {
772   if (pid != (pid_t) INVALID_HANDLE_VALUE)
773     {
774       HANDLE process = (HANDLE) pid;
775       
776       /* Arbitrary error code.  */
777       TerminateProcess (process, 1);
778     }
779 }