1 /* exechelp-w32.c - Fork and exec helpers for W32CE.
2 * Copyright (C) 2004, 2007, 2008, 2009,
3 * 2010 Free Software Foundation, Inc.
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/>.
33 #if !defined(HAVE_W32_SYSTEM) && !defined (HAVE_W32CE_SYSTEM)
34 #error This code is only used on W32CE.
48 #ifdef WITHOUT_NPTH /* Give the Makefile a chance to build without Pth. */
58 # include <sys/stat.h>
69 /* It seems Vista doesn't grok X_OK and so fails access() tests.
70 Previous versions interpreted X_OK as F_OK anyway, so we'll just
76 /* We assume that a HANDLE can be represented by an int which should
77 be true for all i386 systems (HANDLE is defined as void *) and
78 these are the only systems for which Windows is available. Further
79 we assume that -1 denotes an invalid handle. */
80 #define fd_to_handle(a) ((HANDLE)(a))
81 #define handle_to_fd(a) ((int)(a))
82 #define pid_to_handle(a) ((HANDLE)(a))
83 #define handle_to_pid(a) ((int)(a))
87 /* The data passed to the feeder_thread. */
88 struct feeder_thread_parms
91 volatile int stream_valid;
97 /* The thread started by start_feede3. */
99 feeder_thread (void *arg)
101 struct feeder_thread_parms *parm = arg;
110 log_debug ("feeder_thread estream->pipe: stream=%p pipe=%p\n",
111 parm->stream, parm->hd);
112 while (parm->stream_valid
113 && !es_read (parm->stream, buffer, sizeof buffer, &nread))
118 rc = WriteFile (parm->hd, buffer, nread, &nwritten, NULL);
122 log_debug ("feeder(%p): WriteFile error: rc=%d\n",
123 parm->hd, (int)GetLastError ());
130 if (!parm->stream_valid)
131 log_debug ("feeder(%p): closed by other thread\n", parm->hd);
133 log_debug ("feeder(%p): es_read error: %s\n",
134 parm->hd, strerror (errno));
141 log_debug ("feeder_thread pipe->estream: stream=%p pipe=%p\n",
142 parm->stream, parm->hd);
143 while ( (pth_enter (),
144 (rc = ReadFile (parm->hd, buffer, sizeof buffer, &nread, NULL)),
148 log_debug ("feeder_thread pipe->estream: read %d bytes\n",
152 if (parm->stream_valid
153 && es_write (parm->stream, buffer, nread, &nwritten))
155 log_debug ("feeder(%p): es_write error: %s\n",
156 parm->hd, strerror (errno));
159 log_debug ("feeder_thread pipe->estream: es_wrote %d bytes\n",
163 while (nread && parm->stream_valid);
165 if (!parm->stream_valid)
166 log_debug ("feeder(%p): closed by other thread\n", parm->hd);
168 log_debug ("feeder(%p): ReadFile error: rc=%d\n",
169 parm->hd, (int)GetLastError ());
171 log_debug ("feeder(%p): eof\n", parm->hd);
175 log_debug ("feeder(%p): waiting for es_fclose\n", parm->hd);
176 while (parm->stream_valid)
178 log_debug ("feeder(%p): about to close the pipe handle\n", parm->hd);
179 CloseHandle (parm->hd);
180 log_debug ("feeder(%p): pipe handle closed\n", parm->hd);
188 feeder_onclose_notification (estream_t stream, void *opaque)
190 struct feeder_thread_parms *parm = opaque;
192 log_debug ("feeder(%p): received onclose note\n", parm->hd);
193 parm->stream_valid = 0;
197 /* Fire up a thread to copy data between STREAM and a pipe's
198 descriptor FD. With DIRECTION set to true the copy takes place
199 from the stream to the pipe, otherwise from the pipe to the
202 start_feeder (estream_t stream, HANDLE hd, int direction)
206 struct feeder_thread_parms *parm;
209 parm = xtrymalloc (sizeof *parm);
211 return gpg_error_from_syserror ();
212 parm->stream = stream;
213 parm->stream_valid = 1;
215 parm->direction = direction;
217 if (es_onclose (stream, 1, feeder_onclose_notification, parm))
219 err = gpg_error_from_syserror ();
224 tattr = pth_attr_new ();
225 pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
226 pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
227 pth_attr_set (tattr, PTH_ATTR_NAME, "exec-feeder");
229 log_debug ("spawning new feeder(%p, %p, %d)\n", stream, hd, direction);
230 if(!pth_spawn (tattr, feeder_thread, parm))
232 err = gpg_error_from_syserror ();
233 es_onclose (stream, 0, feeder_onclose_notification, parm);
238 pth_attr_destroy (tattr);
245 return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* No Pth. */
251 /* Return the maximum number of currently allowed open file
252 descriptors. Only useful on POSIX systems but returns a value on
253 other systems too. */
265 max_fds = 256; /* Arbitrary limit. */
271 /* Under Windows this is a dummy function. */
273 close_all_fds (int first, int *except)
280 /* Returns an array with all currently open file descriptors. The end
281 of the array is marked by -1. The caller needs to release this
282 array using the *standard free* and not with xfree. This allow the
283 use of this function right at startup even before libgcrypt has
284 been initialized. Returns NULL on error and sets ERRNO
287 get_all_open_fds (void)
293 array = calloc (1, sizeof *array);
299 max_fd = get_max_fds ();
300 narray = 32; /* If you change this change also t-exechelp.c. */
301 array = calloc (narray, sizeof *array);
305 /* Note: The list we return is ordered. */
306 for (idx=0, fd=0; fd < max_fd; fd++)
307 if (!(fstat (fd, &statbuf) == -1 && errno == EBADF))
313 narray += (narray < 256)? 32:256;
314 tmp = realloc (array, narray * sizeof *array);
332 copy_quoted (char *p, const char *string)
336 if (!*string) /* Empty string. */
337 p = stpcpy (p, "\"\"");
338 else if (strpbrk (string, " \t\n\v\f\"")) /* Need quotes. */
340 p = stpcpy (p, "\"");
341 for (s = string; *s; s++)
350 else /* Copy verbatim. */
351 p = stpcpy (p, string);
357 /* Build a command line for use with W32's CreateProcess. On success
358 CMDLINE gets the address of a newly allocated string. */
360 build_w32_commandline (const char * const *argv,
361 int rvid0, int rvid1, int rvid2,
373 snprintf (p, 25, "-&S0=%d ", rvid0);
375 strcpy (p, "-&S0=null ");
379 snprintf (p, 25, "-&S1=%d ", rvid1);
381 strcpy (p, "-&S1=null ");
385 snprintf (p, 25, "-&S2=%d ", rvid2);
387 strcpy (p, "-&S2=null ");
392 for (i=0; (s = argv[i]); i++)
394 n += strlen (s) + 1 + 2; /* (1 space, 2 quoting) */
397 n++; /* Need to double inner quotes. */
401 buf = p = xtrymalloc (n);
405 p = stpcpy (p, fdbuf);
406 for (i = 0; argv[i]; i++)
409 p = copy_quoted (p, argv[i]);
417 /* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
418 the read end is inheritable, with 1 the write end is inheritable.
419 Note that the inheritable ends are rendezvous ids and no file
420 descriptors or handles. */
422 create_inheritable_pipe (int filedes[2], int inherit_idx)
427 filedes[0] = filedes[1] = -1;
428 hd = _assuan_w32ce_prepare_pipe (&rvid, !inherit_idx);
429 if (hd == INVALID_HANDLE_VALUE)
431 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n", w32_strerror (-1));
432 gpg_err_set_errno (EIO);
433 return gpg_error_from_syserror ();
438 filedes[0] = handle_to_fd (hd);
444 filedes[1] = handle_to_fd (hd);
450 /* Portable function to create a pipe. Under Windows the write end is
451 inheritable (i.e. an rendezvous id). */
453 gnupg_create_inbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
456 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
458 return create_inheritable_pipe (filedes, 1);
462 /* Portable function to create a pipe. Under Windows the read end is
463 inheritable (i.e. an rendezvous id). */
465 gnupg_create_outbound_pipe (int filedes[2], estream_t *r_fp, int nonblock)
468 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
470 return create_inheritable_pipe (filedes, 0);
474 /* Portable function to create a pipe. Under Windows both ends are
477 gnupg_create_pipe (int filedes[2])
479 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
484 create_process (const char *pgmname, const char *cmdline,
485 PROCESS_INFORMATION *pi)
488 wchar_t *wpgmname, *wcmdline;
490 wpgmname = utf8_to_wchar (pgmname);
493 wcmdline = utf8_to_wchar (cmdline);
499 res = CreateProcess (wpgmname, /* Program to start. */
500 wcmdline, /* Command line arguments. */
501 NULL, /* Process security attributes. */
502 NULL, /* Thread security attributes. */
503 FALSE, /* Inherit handles. */
504 CREATE_SUSPENDED, /* Creation flags. */
505 NULL, /* Environment. */
506 NULL, /* Use current drive/directory. */
507 NULL, /* Startup information. */
508 pi); /* Returns process information. */
515 /* Fork and exec the PGMNAME, see exechelp.h for details. */
517 gnupg_spawn_process (const char *pgmname, const char *argv[],
518 int *except, void (*preexec)(void), unsigned int flags,
525 PROCESS_INFORMATION pi = {NULL };
531 } inpipe = {INVALID_HANDLE_VALUE, 0};
535 } outpipe = {INVALID_HANDLE_VALUE, 0};
539 } errpipe = {INVALID_HANDLE_VALUE, 0};
540 estream_t outfp = NULL;
541 estream_t errfp = NULL;
542 gpg_err_source_t errsource = default_errsource;
544 (void)except; /* Not yet used. */
548 /* Setup return values. */
553 *pid = (pid_t)(-1); /* Always required. */
555 log_debug ("%s: enter\n", __func__);
561 /* Create a pipe to copy our infile to the stdin of the child
562 process. On success inpipe.hd is owned by the feeder. */
563 inpipe.hd = _assuan_w32ce_prepare_pipe (&inpipe.rvid, 1);
564 if (inpipe.hd == INVALID_HANDLE_VALUE)
566 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
568 gpg_err_set_errno (EIO);
569 return gpg_error_from_syserror ();
571 log_debug ("%s: inpipe %p created; hd=%p rvid=%d\n", __func__,
572 infp, inpipe.hd, inpipe.rvid);
573 err = start_feeder (infp, inpipe.hd, 1);
576 log_error ("error spawning feeder: %s\n", gpg_strerror (err));
577 CloseHandle (inpipe.hd);
580 inpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the feeder. */
581 log_debug ("%s: inpipe %p created; feeder started\n", __func__,
587 /* Create a pipe to make the stdout of the child process
588 available as a stream. */
589 outpipe.hd = _assuan_w32ce_prepare_pipe (&outpipe.rvid, 0);
590 if (outpipe.hd == INVALID_HANDLE_VALUE)
592 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
594 gpg_err_set_errno (EIO);
595 /* Fixme release other stuff/kill feeder. */
596 return gpg_error_from_syserror ();
598 syshd.type = ES_SYSHD_HANDLE;
599 syshd.u.handle = outpipe.hd;
601 outfp = es_sysopen (&syshd, "r");
604 err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
605 log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
606 CloseHandle (outpipe.hd);
609 log_debug ("%s: outpipe %p created; hd=%p rvid=%d\n", __func__,
610 outfp, outpipe.hd, outpipe.rvid);
611 outpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the OUTFP. */
616 /* Create a pipe to make the stderr of the child process
617 available as a stream. */
618 errpipe.hd = _assuan_w32ce_prepare_pipe (&errpipe.rvid, 0);
619 if (errpipe.hd == INVALID_HANDLE_VALUE)
621 log_error ("_assuan_w32ce_prepare_pipe failed: %s\n",
623 gpg_err_set_errno (EIO);
624 /* Fixme release other stuff/kill feeder. */
625 return gpg_error_from_syserror ();
627 syshd.type = ES_SYSHD_HANDLE;
628 syshd.u.handle = errpipe.hd;
630 errfp = es_sysopen (&syshd, "r");
633 err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
634 log_error ("error opening pipe stream: %s\n", gpg_strerror (err));
635 CloseHandle (errpipe.hd);
638 log_debug ("%s: errpipe %p created; hd=%p rvid=%d\n", __func__,
639 errfp, errpipe.hd, errpipe.rvid);
640 errpipe.hd = INVALID_HANDLE_VALUE; /* Now owned by the ERRFP. */
645 /* Build the command line. */
646 err = build_w32_commandline (argv, inpipe.rvid, outpipe.rvid, errpipe.rvid,
650 /* Fixme release other stuff/kill feeder. */
651 CloseHandle (errpipe.hd);
655 log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
656 if (!create_process (pgmname, cmdline, &pi))
658 log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
660 /* Fixme release other stuff/kill feeder. */
661 CloseHandle (errpipe.hd);
662 return gpg_error (GPG_ERR_GENERAL);
667 /* Note: The other end of the pipe is a rendezvous id and thus there
668 is no need for a close. */
670 log_debug ("CreateProcess ready: hProcess=%p hThread=%p"
671 " dwProcessID=%d dwThreadId=%d\n",
672 pi.hProcess, pi.hThread,
673 (int) pi.dwProcessId, (int) pi.dwThreadId);
676 /* Process has been created suspended; resume it now. */
677 ResumeThread (pi.hThread);
678 CloseHandle (pi.hThread);
684 *pid = handle_to_pid (pi.hProcess);
690 /* Simplified version of gnupg_spawn_process. This function forks and
691 then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
692 and ERRFD to stderr (any of them may be -1 to connect them to
693 /dev/null). The arguments for the process are expected in the NULL
694 terminated array ARGV. The program name itself should not be
695 included there. Calling gnupg_wait_process is required.
697 Returns 0 on success or an error code. */
699 gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
700 int infd, int outfd, int errfd, pid_t *pid)
703 PROCESS_INFORMATION pi = {NULL};
706 /* Setup return values. */
709 if (infd != -1 || outfd != -1 || errfd != -1)
710 return gpg_error (GPG_ERR_NOT_SUPPORTED);
712 /* Build the command line. */
713 err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
717 log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
718 if (!create_process (pgmname, cmdline, &pi))
720 log_error ("CreateProcess(fd) failed: %s\n", w32_strerror (-1));
722 return gpg_error (GPG_ERR_GENERAL);
727 log_debug ("CreateProcess(fd) ready: hProcess=%p hThread=%p"
728 " dwProcessID=%d dwThreadId=%d\n",
729 pi.hProcess, pi.hThread,
730 (int) pi.dwProcessId, (int) pi.dwThreadId);
732 /* Process has been created suspended; resume it now. */
733 ResumeThread (pi.hThread);
734 CloseHandle (pi.hThread);
736 *pid = handle_to_pid (pi.hProcess);
741 /* See exechelp.h for a description. */
743 gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *exitcode)
746 HANDLE proc = fd_to_handle (pid);
753 if (pid == (pid_t)(-1))
754 return gpg_error (GPG_ERR_INV_VALUE);
756 /* FIXME: We should do a pth_waitpid here. However this has not yet
757 been implemented. A special W32 pth system call would even be
759 code = WaitForSingleObject (proc, hang? INFINITE : 0);
763 ec = GPG_ERR_TIMEOUT;
767 log_error (_("waiting for process %d to terminate failed: %s\n"),
768 (int)pid, w32_strerror (-1));
769 ec = GPG_ERR_GENERAL;
773 if (!GetExitCodeProcess (proc, &exc))
775 log_error (_("error getting exit code of process %d: %s\n"),
776 (int)pid, w32_strerror (-1) );
777 ec = GPG_ERR_GENERAL;
781 log_error (_("error running '%s': exit status %d\n"),
784 *exitcode = (int)exc;
785 ec = GPG_ERR_GENERAL;
796 log_error ("WaitForSingleObject returned unexpected "
797 "code %d for pid %d\n", code, (int)pid );
798 ec = GPG_ERR_GENERAL;
802 return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
806 /* See exechelp.h for a description. */
808 gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
809 int hang, int *r_exitcodes)
811 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
816 gnupg_release_process (pid_t pid)
818 if (pid != (pid_t)INVALID_HANDLE_VALUE)
820 HANDLE process = (HANDLE)pid;
822 CloseHandle (process);
827 /* Spawn a new process and immediately detach from it. The name of
828 the program to exec is PGMNAME and its arguments are in ARGV (the
829 programname is automatically passed as first argument).
830 Environment strings in ENVP are set. An error is returned if
831 pgmname is not executable; to make this work it is necessary to
832 provide an absolute file name. All standard file descriptors are
833 connected to /dev/null. */
835 gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
840 PROCESS_INFORMATION pi = {NULL };
844 /* Build the command line. */
845 err = build_w32_commandline (argv, 0, 0, 0, &cmdline);
849 /* Note: There is no detached flag under CE. */
850 log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline);
851 if (!create_process (pgmname, cmdline, &pi))
853 log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
855 return gpg_error (GPG_ERR_GENERAL);
860 log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p"
861 " dwProcessID=%d dwThreadId=%d\n",
862 pi.hProcess, pi.hThread,
863 (int) pi.dwProcessId, (int) pi.dwThreadId);
865 /* Process has been created suspended; resume it now. */
866 ResumeThread (pi.hThread);
867 CloseHandle (pi.hThread);
873 /* Kill a process; that is send an appropriate signal to the process.
874 gnupg_wait_process must be called to actually remove the process
875 from the system. An invalid PID is ignored. */
877 gnupg_kill_process (pid_t pid)
879 if (pid != (pid_t) INVALID_HANDLE_VALUE)
881 HANDLE process = (HANDLE) pid;
883 /* Arbitrary error code. */
884 TerminateProcess (process, 1);