1 /* exechelp-w32.c - Fork and exec helpers for W32.
2 * Copyright (C) 2004, 2007-2009, 2010 Free Software Foundation, Inc.
3 * Copyright (C) 2004, 2006-2012, 2014-2017 g10 Code GmbH
5 * This file is part of GnuPG.
7 * This file is free software; you can redistribute it and/or modify
8 * it under the terms of either
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.
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.
20 * or both in parallel, as here.
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.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, see <https://www.gnu.org/licenses/>.
29 * SPDX-License-Identifier: (LGPL-3.0+ OR GPL-2.0+)
34 #if !defined(HAVE_W32_SYSTEM)
35 #error This code is only used on W32.
49 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
59 # include <sys/stat.h>
70 /* Define to 1 do enable debugging. */
71 #define DEBUG_W32_SPAWN 0
74 /* It seems Vista doesn't grok X_OK and so fails access() tests.
75 Previous versions interpreted X_OK as F_OK anyway, so we'll just
80 /* We assume that a HANDLE can be represented by an intptr_t which
81 should be true for all systems (HANDLE is defined as void *).
82 Further we assume that -1 denotes an invalid handle. */
83 # define fd_to_handle(a) ((HANDLE)(a))
84 # define handle_to_fd(a) ((intptr_t)(a))
85 # define pid_to_handle(a) ((HANDLE)(a))
86 # define handle_to_pid(a) ((int)(a))
90 static inline gpg_error_t
91 my_error_from_syserror (void)
93 return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
96 static inline gpg_error_t
97 my_error (int errcode)
99 return gpg_err_make (default_errsource, errcode);
103 /* Return the maximum number of currently allowed open file
104 descriptors. Only useful on POSIX systems but returns a value on
105 other systems too. */
117 max_fds = 256; /* Arbitrary limit. */
123 /* Under Windows this is a dummy function. */
125 close_all_fds (int first, int *except)
132 /* Returns an array with all currently open file descriptors. The end
133 * of the array is marked by -1. The caller needs to release this
134 * array using the *standard free* and not with xfree. This allow the
135 * use of this function right at startup even before libgcrypt has
136 * been initialized. Returns NULL on error and sets ERRNO
137 * accordingly. Note that fstat prints a warning to DebugView for all
138 * invalid fds which is a bit annoying. We actually do not need this
139 * function in real code (close_all_fds is a dummy anyway) but we keep
140 * it for use by t-exechelp.c. */
142 get_all_open_fds (void)
148 array = calloc (1, sizeof *array);
154 max_fd = get_max_fds ();
155 narray = 32; /* If you change this change also t-exechelp.c. */
156 array = calloc (narray, sizeof *array);
160 /* Note: The list we return is ordered. */
161 for (idx=0, fd=0; fd < max_fd; fd++)
162 if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
168 narray += (narray < 256)? 32:256;
169 tmp = realloc (array, narray * sizeof *array);
185 /* Helper function to build_w32_commandline. */
187 build_w32_commandline_copy (char *buffer, const char *string)
192 if (!*string) /* Empty string. */
193 p = stpcpy (p, "\"\"");
194 else if (strpbrk (string, " \t\n\v\f\""))
196 /* Need to do some kind of quoting. */
197 p = stpcpy (p, "\"");
198 for (s=string; *s; s++)
208 p = stpcpy (p, string);
213 /* Build a command line for use with W32's CreateProcess. On success
214 CMDLINE gets the address of a newly allocated string. */
216 build_w32_commandline (const char *pgmname, const char * const *argv,
226 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
229 n++; /* Need to double inner quotes. */
230 for (i=0; (s=argv[i]); i++)
232 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting */
235 n++; /* Need to double inner quotes. */
239 buf = p = xtrymalloc (n);
241 return my_error_from_syserror ();
243 p = build_w32_commandline_copy (p, pgmname);
244 for (i=0; argv[i]; i++)
247 p = build_w32_commandline_copy (p, argv[i]);
255 #define INHERIT_READ 1
256 #define INHERIT_WRITE 2
257 #define INHERIT_BOTH (INHERIT_READ|INHERIT_WRITE)
259 /* Create pipe. FLAGS indicates which ends are inheritable. */
261 create_inheritable_pipe (HANDLE filedes[2], int flags)
264 SECURITY_ATTRIBUTES sec_attr;
266 memset (&sec_attr, 0, sizeof sec_attr );
267 sec_attr.nLength = sizeof sec_attr;
268 sec_attr.bInheritHandle = TRUE;
270 if (!CreatePipe (&r, &w, &sec_attr, 0))
273 if ((flags & INHERIT_READ) == 0)
274 if (! SetHandleInformation (r, HANDLE_FLAG_INHERIT, 0))
277 if ((flags & INHERIT_WRITE) == 0)
278 if (! SetHandleInformation (w, HANDLE_FLAG_INHERIT, 0))
286 log_error ("SetHandleInformation failed: %s\n", w32_strerror (-1));
294 w32_open_null (int for_write)
298 hfile = CreateFileW (L"nul",
299 for_write? GENERIC_WRITE : GENERIC_READ,
300 FILE_SHARE_READ | FILE_SHARE_WRITE,
301 NULL, OPEN_EXISTING, 0, NULL);
302 if (hfile == INVALID_HANDLE_VALUE)
303 log_debug ("can't open 'nul': %s\n", w32_strerror (-1));
309 create_pipe_and_estream (int filedes[2], int flags,
310 estream_t *r_fp, int outbound, int nonblock)
316 filedes[0] = filedes[1] = -1;
317 err = my_error (GPG_ERR_GENERAL);
318 if (!create_inheritable_pipe (fds, flags))
320 filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), O_RDONLY);
321 if (filedes[0] == -1)
323 log_error ("failed to translate osfhandle %p\n", fds[0]);
324 CloseHandle (fds[1]);
328 filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), O_APPEND);
329 if (filedes[1] == -1)
331 log_error ("failed to translate osfhandle %p\n", fds[1]);
334 CloseHandle (fds[1]);
343 syshd.type = ES_SYSHD_HANDLE;
346 syshd.u.handle = fds[0];
347 *r_fp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
351 syshd.u.handle = fds[1];
352 *r_fp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
356 err = my_error_from_syserror ();
357 log_error (_("error creating a stream for a pipe: %s\n"),
361 filedes[0] = filedes[1] = -1;
369 /* Portable function to create a pipe. Under Windows the write end is
370 inheritable. If R_FP is not NULL, an estream is created for the
371 read end and stored at R_FP. */
373 gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
375 return create_pipe_and_estream (filedes, INHERIT_WRITE,
380 /* Portable function to create a pipe. Under Windows the read end is
381 inheritable. If R_FP is not NULL, an estream is created for the
382 write end and stored at R_FP. */
384 gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
386 return create_pipe_and_estream (filedes, INHERIT_READ,
391 /* Portable function to create a pipe. Under Windows both ends are
394 gnupg_create_pipe (int filedes[2])
396 return create_pipe_and_estream (filedes, INHERIT_BOTH,
401 /* Close the end of a pipe. */
403 gnupg_close_pipe (int fd)
410 /* Fork and exec the PGMNAME, see exechelp.h for details. */
412 gnupg_spawn_process (const char *pgmname, const char *argv[],
413 int *except, unsigned int flags,
420 SECURITY_ATTRIBUTES sec_attr;
421 PROCESS_INFORMATION pi =
423 NULL, /* Returns process handle. */
424 0, /* Returns primary thread handle. */
425 0, /* Returns pid. */
431 wchar_t *wcmdline = NULL;
432 wchar_t *wpgmname = NULL;
433 HANDLE inpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
434 HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
435 HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
436 estream_t infp = NULL;
437 estream_t outfp = NULL;
438 estream_t errfp = NULL;
439 HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
440 INVALID_HANDLE_VALUE,
441 INVALID_HANDLE_VALUE};
444 gpg_err_source_t errsource = default_errsource;
445 int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
447 (void)except; /* Not yet used. */
455 *pid = (pid_t)(-1); /* Always required. */
459 if (create_inheritable_pipe (inpipe, INHERIT_READ))
461 err = gpg_err_make (errsource, GPG_ERR_GENERAL);
462 log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
466 syshd.type = ES_SYSHD_HANDLE;
467 syshd.u.handle = inpipe[1];
468 infp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
471 err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
472 log_error (_("error creating a stream for a pipe: %s\n"),
474 CloseHandle (inpipe[0]);
475 CloseHandle (inpipe[1]);
476 inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE;
483 if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
485 err = gpg_err_make (errsource, GPG_ERR_GENERAL);
486 log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
490 syshd.type = ES_SYSHD_HANDLE;
491 syshd.u.handle = outpipe[0];
492 outfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
495 err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
496 log_error (_("error creating a stream for a pipe: %s\n"),
498 CloseHandle (outpipe[0]);
499 CloseHandle (outpipe[1]);
500 outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
503 else if (inpipe[1] != INVALID_HANDLE_VALUE)
504 CloseHandle (inpipe[1]);
505 if (inpipe[0] != INVALID_HANDLE_VALUE)
506 CloseHandle (inpipe[0]);
513 if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
515 err = gpg_err_make (errsource, GPG_ERR_GENERAL);
516 log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
520 syshd.type = ES_SYSHD_HANDLE;
521 syshd.u.handle = errpipe[0];
522 errfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
525 err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
526 log_error (_("error creating a stream for a pipe: %s\n"),
528 CloseHandle (errpipe[0]);
529 CloseHandle (errpipe[1]);
530 errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
533 else if (outpipe[0] != INVALID_HANDLE_VALUE)
534 CloseHandle (outpipe[0]);
535 if (outpipe[1] != INVALID_HANDLE_VALUE)
536 CloseHandle (outpipe[1]);
539 else if (inpipe[1] != INVALID_HANDLE_VALUE)
540 CloseHandle (inpipe[1]);
541 if (inpipe[0] != INVALID_HANDLE_VALUE)
542 CloseHandle (inpipe[0]);
547 /* Prepare security attributes. */
548 memset (&sec_attr, 0, sizeof sec_attr );
549 sec_attr.nLength = sizeof sec_attr;
550 sec_attr.bInheritHandle = FALSE;
552 /* Build the command line. */
553 err = build_w32_commandline (pgmname, argv, &cmdline);
557 if (inpipe[0] == INVALID_HANDLE_VALUE)
558 nullhd[0] = ((flags & GNUPG_SPAWN_KEEP_STDIN)?
559 GetStdHandle (STD_INPUT_HANDLE) : w32_open_null (0));
560 if (outpipe[1] == INVALID_HANDLE_VALUE)
561 nullhd[1] = ((flags & GNUPG_SPAWN_KEEP_STDOUT)?
562 GetStdHandle (STD_OUTPUT_HANDLE) : w32_open_null (1));
563 if (errpipe[1] == INVALID_HANDLE_VALUE)
564 nullhd[2] = ((flags & GNUPG_SPAWN_KEEP_STDOUT)?
565 GetStdHandle (STD_ERROR_HANDLE) : w32_open_null (1));
567 memset (&si, 0, sizeof si);
569 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
570 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE;
571 si.hStdInput = inpipe[0] == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
572 si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
573 si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
575 cr_flags = (CREATE_DEFAULT_ERROR_MODE
576 | ((flags & GNUPG_SPAWN_DETACHED)? DETACHED_PROCESS : 0)
577 | GetPriorityClass (GetCurrentProcess ())
579 /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", */
580 /* pgmname, cmdline); */
581 /* Take care: CreateProcessW may modify wpgmname */
582 if (!(wpgmname = utf8_to_wchar (pgmname)))
584 else if (!(wcmdline = utf8_to_wchar (cmdline)))
587 rc = CreateProcessW (wpgmname, /* Program to start. */
588 wcmdline, /* Command line arguments. */
589 &sec_attr, /* Process security attributes. */
590 &sec_attr, /* Thread security attributes. */
591 TRUE, /* Inherit handles. */
592 cr_flags, /* Creation flags. */
593 NULL, /* Environment. */
594 NULL, /* Use current drive/directory. */
595 &si, /* Startup information. */
596 &pi /* Returns process information. */
600 if (!wpgmname || !wcmdline)
601 log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
604 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
610 else if (inpipe[1] != INVALID_HANDLE_VALUE)
611 CloseHandle (outpipe[1]);
612 if (inpipe[0] != INVALID_HANDLE_VALUE)
613 CloseHandle (inpipe[0]);
616 else if (outpipe[0] != INVALID_HANDLE_VALUE)
617 CloseHandle (outpipe[0]);
618 if (outpipe[1] != INVALID_HANDLE_VALUE)
619 CloseHandle (outpipe[1]);
622 else if (errpipe[0] != INVALID_HANDLE_VALUE)
623 CloseHandle (errpipe[0]);
624 if (errpipe[1] != INVALID_HANDLE_VALUE)
625 CloseHandle (errpipe[1]);
626 return gpg_err_make (errsource, GPG_ERR_GENERAL);
633 /* Close the inherited handles to /dev/null. */
634 for (i=0; i < DIM (nullhd); i++)
635 if (nullhd[i] != INVALID_HANDLE_VALUE)
636 CloseHandle (nullhd[i]);
638 /* Close the inherited ends of the pipes. */
639 if (inpipe[0] != INVALID_HANDLE_VALUE)
640 CloseHandle (inpipe[0]);
641 if (outpipe[1] != INVALID_HANDLE_VALUE)
642 CloseHandle (outpipe[1]);
643 if (errpipe[1] != INVALID_HANDLE_VALUE)
644 CloseHandle (errpipe[1]);
646 /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
647 /* " dwProcessID=%d dwThreadId=%d\n", */
648 /* pi.hProcess, pi.hThread, */
649 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
650 /* log_debug (" outfp=%p errfp=%p\n", outfp, errfp); */
652 /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
653 invalid argument error if we pass it the correct processID. As a
654 workaround we use -1 (ASFW_ANY). */
655 if ((flags & GNUPG_SPAWN_RUN_ASFW))
656 gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
658 /* Process has been created suspended; resume it now. */
659 ResumeThread (pi.hThread);
660 CloseHandle (pi.hThread);
669 *pid = handle_to_pid (pi.hProcess);
676 /* Simplified version of gnupg_spawn_process. This function forks and
677 then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
678 and ERRFD to stderr (any of them may be -1 to connect them to
679 /dev/null). The arguments for the process are expected in the NULL
680 terminated array ARGV. The program name itself should not be
681 included there. Calling gnupg_wait_process is required.
683 Returns 0 on success or an error code. */
685 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
686 int infd, int outfd, int errfd, pid_t *pid)
689 SECURITY_ATTRIBUTES sec_attr;
690 PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
693 wchar_t *wcmdline = NULL;
694 wchar_t *wpgmname = NULL;
698 /* Setup return values. */
701 /* Prepare security attributes. */
702 memset (&sec_attr, 0, sizeof sec_attr );
703 sec_attr.nLength = sizeof sec_attr;
704 sec_attr.bInheritHandle = FALSE;
706 /* Build the command line. */
707 err = build_w32_commandline (pgmname, argv, &cmdline);
711 memset (&si, 0, sizeof si);
713 si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
714 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
715 stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
716 stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
717 stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
718 si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd);
719 si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
720 si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
722 /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
723 /* Take care: CreateProcessW may modify wpgmname */
724 if (!(wpgmname = utf8_to_wchar (pgmname)))
726 else if (!(wcmdline = utf8_to_wchar (cmdline)))
729 rc = CreateProcessW (wpgmname, /* Program to start. */
730 wcmdline, /* Command line arguments. */
731 &sec_attr, /* Process security attributes. */
732 &sec_attr, /* Thread security attributes. */
733 TRUE, /* Inherit handles. */
734 (CREATE_DEFAULT_ERROR_MODE
735 | GetPriorityClass (GetCurrentProcess ())
736 | CREATE_SUSPENDED | DETACHED_PROCESS),
737 NULL, /* Environment. */
738 NULL, /* Use current drive/directory. */
739 &si, /* Startup information. */
740 &pi /* Returns process information. */
744 if (!wpgmname || !wcmdline)
745 log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
748 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
749 err = my_error (GPG_ERR_GENERAL);
756 for (i=0; i < 3; i++)
757 if (stdhd[i] != INVALID_HANDLE_VALUE)
758 CloseHandle (stdhd[i]);
762 /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
763 /* " dwProcessID=%d dwThreadId=%d\n", */
764 /* pi.hProcess, pi.hThread, */
765 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
767 /* Process has been created suspended; resume it now. */
768 ResumeThread (pi.hThread);
769 CloseHandle (pi.hThread);
771 *pid = handle_to_pid (pi.hProcess);
777 /* See exechelp.h for a description. */
779 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
781 return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
784 /* See exechelp.h for a description. */
786 gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
787 int hang, int *r_exitcodes)
789 gpg_err_code_t ec = 0;
794 procs = xtrycalloc (count, sizeof *procs);
796 return my_error_from_syserror ();
798 for (i = 0; i < count; i++)
803 if (pids[i] == (pid_t)(-1))
804 return my_error (GPG_ERR_INV_VALUE);
806 procs[i] = pid_to_handle (pids[i]);
809 /* FIXME: We should do a pth_waitpid here. However this has not yet
810 been implemented. A special W32 pth system call would even be
812 code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
816 ec = GPG_ERR_TIMEOUT;
820 log_error (_("waiting for processes to terminate failed: %s\n"),
822 ec = GPG_ERR_GENERAL;
826 for (i = 0; i < count; i++)
830 if (! GetExitCodeProcess (procs[i], &exc))
832 log_error (_("error getting exit code of process %d: %s\n"),
833 (int) pids[i], w32_strerror (-1) );
834 ec = GPG_ERR_GENERAL;
839 log_error (_("error running '%s': exit status %d\n"),
840 pgmnames[i], (int)exc);
842 r_exitcodes[i] = (int)exc;
843 ec = GPG_ERR_GENERAL;
854 log_error ("WaitForMultipleObjects returned unexpected "
856 ec = GPG_ERR_GENERAL;
861 return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
867 gnupg_release_process (pid_t pid)
869 if (pid != (pid_t)INVALID_HANDLE_VALUE)
871 HANDLE process = (HANDLE)pid;
873 CloseHandle (process);
878 /* Spawn a new process and immediately detach from it. The name of
879 the program to exec is PGMNAME and its arguments are in ARGV (the
880 programname is automatically passed as first argument).
881 Environment strings in ENVP are set. An error is returned if
882 pgmname is not executable; to make this work it is necessary to
883 provide an absolute file name. All standard file descriptors are
884 connected to /dev/null. */
886 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
890 SECURITY_ATTRIBUTES sec_attr;
891 PROCESS_INFORMATION pi =
893 NULL, /* Returns process handle. */
894 0, /* Returns primary thread handle. */
895 0, /* Returns pid. */
901 wchar_t *wcmdline = NULL;
902 wchar_t *wpgmname = NULL;
908 /* We don't use ENVP. */
911 cmdline = getenv ("GNUPG_EXEC_DEBUG_FLAGS");
912 jobdebug = (cmdline && (atoi (cmdline) & 1));
914 if ((ec = gnupg_access (pgmname, X_OK)))
915 return gpg_err_make (default_errsource, ec);
917 /* Prepare security attributes. */
918 memset (&sec_attr, 0, sizeof sec_attr );
919 sec_attr.nLength = sizeof sec_attr;
920 sec_attr.bInheritHandle = FALSE;
922 /* Build the command line. */
923 err = build_w32_commandline (pgmname, argv, &cmdline);
927 /* Start the process. */
928 memset (&si, 0, sizeof si);
930 si.dwFlags = STARTF_USESHOWWINDOW;
931 si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
933 cr_flags = (CREATE_DEFAULT_ERROR_MODE
934 | GetPriorityClass (GetCurrentProcess ())
935 | CREATE_NEW_PROCESS_GROUP
938 /* Check if we were spawned as part of a Job.
939 * In a job we need to add CREATE_BREAKAWAY_FROM_JOB
940 * to the cr_flags, otherwise our child processes
941 * are killed when we terminate. */
942 if (!IsProcessInJob (GetCurrentProcess(), NULL, &in_job))
944 log_error ("IsProcessInJob() failed: %s\n", w32_strerror (-1));
950 /* Only try to break away from job if it is allowed, otherwise
951 * CreateProcess() would fail with an "Access is denied" error. */
952 JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
953 if (!QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation,
954 &info, sizeof info, NULL))
956 log_error ("QueryInformationJobObject() failed: %s\n",
959 else if ((info.BasicLimitInformation.LimitFlags &
960 JOB_OBJECT_LIMIT_BREAKAWAY_OK))
963 log_debug ("Using CREATE_BREAKAWAY_FROM_JOB flag\n");
964 cr_flags |= CREATE_BREAKAWAY_FROM_JOB;
966 else if ((info.BasicLimitInformation.LimitFlags &
967 JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))
969 /* The child process should automatically detach from the job. */
971 log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag; "
972 "JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK is set\n");
976 /* It seems that the child process must remain in the job.
977 * This is not necessarily an error, although it can cause premature
978 * termination of the child process when the job is closed. */
980 log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag\n");
986 log_debug ("Process is not in a Job\n");
989 /* log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
990 /* pgmname, cmdline); */
991 /* Take care: CreateProcessW may modify wpgmname */
992 if (!(wpgmname = utf8_to_wchar (pgmname)))
994 else if (!(wcmdline = utf8_to_wchar (cmdline)))
997 rc = CreateProcessW (wpgmname, /* Program to start. */
998 wcmdline, /* Command line arguments. */
999 &sec_attr, /* Process security attributes. */
1000 &sec_attr, /* Thread security attributes. */
1001 FALSE, /* Inherit handles. */
1002 cr_flags, /* Creation flags. */
1003 NULL, /* Environment. */
1004 NULL, /* Use current drive/directory. */
1005 &si, /* Startup information. */
1006 &pi /* Returns process information. */
1010 if (!wpgmname || !wcmdline)
1011 log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
1014 log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
1018 return my_error (GPG_ERR_GENERAL);
1025 /* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
1026 /* " dwProcessID=%d dwThreadId=%d\n", */
1027 /* pi.hProcess, pi.hThread, */
1028 /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
1030 CloseHandle (pi.hThread);
1031 CloseHandle (pi.hProcess);
1037 /* Kill a process; that is send an appropriate signal to the process.
1038 gnupg_wait_process must be called to actually remove the process
1039 from the system. An invalid PID is ignored. */
1041 gnupg_kill_process (pid_t pid)
1043 if (pid != (pid_t) INVALID_HANDLE_VALUE)
1045 HANDLE process = (HANDLE) pid;
1047 /* Arbitrary error code. */
1048 TerminateProcess (process, 1);