aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--agent/genkey.c20
-rw-r--r--common/asshelp.c12
-rw-r--r--common/exechelp-posix.c679
-rw-r--r--common/exechelp-w32.c757
-rw-r--r--common/exechelp.h102
-rw-r--r--common/exectool.c40
-rw-r--r--dirmngr/ldap-wrapper.c80
-rw-r--r--g10/photoid.c48
-rw-r--r--g13/be-encfs.c65
-rw-r--r--g13/g13.c1
-rw-r--r--g13/mount.c3
-rw-r--r--g13/runner.c36
-rw-r--r--g13/runner.h2
-rw-r--r--scd/app.c24
-rw-r--r--tests/gpgscm/ffi.c222
-rw-r--r--tests/gpgscm/t-child.scm39
-rw-r--r--tests/gpgscm/tests.scm66
-rw-r--r--tests/openpgp/defs.scm7
-rw-r--r--tests/tpm2dtests/defs.scm7
-rw-r--r--tools/gpg-card.c14
-rw-r--r--tools/gpgconf-comp.c145
-rw-r--r--tools/gpgconf.c20
-rw-r--r--tools/gpgtar-create.c31
-rw-r--r--tools/gpgtar-extract.c31
-rw-r--r--tools/gpgtar-list.c33
25 files changed, 2058 insertions, 426 deletions
diff --git a/agent/genkey.c b/agent/genkey.c
index eb6791dca..fb0084193 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -99,7 +99,7 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
estream_t stream_to_check_pattern = NULL;
const char *argv[10];
- pid_t pid;
+ gnupg_process_t proc;
int result, i;
const char *pattern;
char *patternfname;
@@ -142,11 +142,19 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
argv[i] = NULL;
log_assert (i < sizeof argv);
- if (gnupg_spawn_process (pgmname, argv, NULL, 0,
- &stream_to_check_pattern, NULL, NULL, &pid))
+ if (gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_PIPE
+ | GNUPG_PROCESS_STDOUT_NULL
+ | GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc))
result = 1; /* Execute error - assume password should no be used. */
else
{
+ int status;
+
+ gnupg_process_get_streams (proc, 0, &stream_to_check_pattern,
+ NULL, NULL);
+
es_set_binary (stream_to_check_pattern);
if (es_fwrite (pw, strlen (pw), 1, stream_to_check_pattern) != 1)
{
@@ -157,11 +165,13 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
else
es_fflush (stream_to_check_pattern);
es_fclose (stream_to_check_pattern);
- if (gnupg_wait_process (pgmname, pid, 1, NULL))
+ gnupg_process_wait (proc, 1);
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
+ if (status)
result = 1; /* Helper returned an error - probably a match. */
else
result = 0; /* Success; i.e. no match. */
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
}
xfree (patternfname);
diff --git a/common/asshelp.c b/common/asshelp.c
index eb3e41bf5..b65a3686f 100644
--- a/common/asshelp.c
+++ b/common/asshelp.c
@@ -526,13 +526,11 @@ start_new_service (assuan_context_t *r_ctx,
err = gnupg_spawn_process_detached (program? program : program_name,
argv, NULL);
#else /*!W32*/
- pid_t pid;
-
- err = gnupg_spawn_process_fd (program? program : program_name,
- argv, -1, -1, -1, &pid);
- if (!err)
- err = gnupg_wait_process (program? program : program_name,
- pid, 1, NULL);
+ err = gnupg_process_spawn (program? program : program_name, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, NULL);
#endif /*!W32*/
if (err)
log_error ("failed to start %s '%s': %s\n",
diff --git a/common/exechelp-posix.c b/common/exechelp-posix.c
index fa613449d..b29e2f124 100644
--- a/common/exechelp-posix.c
+++ b/common/exechelp-posix.c
@@ -915,3 +915,682 @@ gnupg_kill_process (pid_t pid)
kill (pid, SIGTERM);
}
}
+
+#include <sys/socket.h>
+
+struct gnupg_process {
+ const char *pgmname;
+ unsigned int terminated :1; /* or detached */
+ unsigned int flags;
+ pid_t pid;
+ int fd_in;
+ int fd_out;
+ int fd_err;
+ int wstatus;
+};
+
+static int gnupg_process_syscall_func_initialized;
+
+/* Functions called before and after blocking syscalls. */
+static void (*pre_syscall_func) (void);
+static void (*post_syscall_func) (void);
+
+static void
+check_syscall_func (void)
+{
+ if (!gnupg_process_syscall_func_initialized)
+ {
+ gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
+ gnupg_process_syscall_func_initialized = 1;
+ }
+}
+
+static void
+pre_syscall (void)
+{
+ if (pre_syscall_func)
+ pre_syscall_func ();
+}
+
+static void
+post_syscall (void)
+{
+ if (post_syscall_func)
+ post_syscall_func ();
+}
+
+
+static gpg_err_code_t
+do_create_socketpair (int filedes[2])
+{
+ gpg_error_t err = 0;
+
+ pre_syscall ();
+ if (socketpair (AF_LOCAL, SOCK_STREAM, 0, filedes) == -1)
+ {
+ err = gpg_err_code_from_syserror ();
+ filedes[0] = filedes[1] = -1;
+ }
+ post_syscall ();
+
+ return err;
+}
+
+static int
+posix_open_null (int for_write)
+{
+ int fd;
+
+ fd = open ("/dev/null", for_write? O_WRONLY : O_RDONLY);
+ if (fd == -1)
+ log_fatal ("failed to open '/dev/null': %s\n", strerror (errno));
+ return fd;
+}
+
+static void
+call_spawn_cb (struct spawn_cb_arg *sca,
+ int fd_in, int fd_out, int fd_err,
+ void (*spawn_cb) (struct spawn_cb_arg *), void *spawn_cb_arg)
+{
+ sca->fds[0] = fd_in;
+ sca->fds[1] = fd_out;
+ sca->fds[2] = fd_err;
+ sca->except_fds = NULL;
+ sca->arg = spawn_cb_arg;
+ if (spawn_cb)
+ (*spawn_cb) (sca);
+}
+
+static void
+my_exec (const char *pgmname, const char *argv[], struct spawn_cb_arg *sca)
+{
+ int i;
+
+ /* Assign /dev/null to unused FDs. */
+ for (i = 0; i <= 2; i++)
+ if (sca->fds[i] == -1)
+ sca->fds[i] = posix_open_null (i);
+
+ /* Connect the standard files. */
+ for (i = 0; i <= 2; i++)
+ if (sca->fds[i] != i)
+ {
+ if (dup2 (sca->fds[i], i) == -1)
+ log_fatal ("dup2 std%s failed: %s\n",
+ i==0?"in":i==1?"out":"err", strerror (errno));
+ /*
+ * We don't close sca.fds[i] here, but close them by
+ * close_all_fds. Note that there may be same one in three of
+ * sca->fds[i].
+ */
+ }
+
+ /* Close all other files. */
+ close_all_fds (3, sca->except_fds);
+
+ execv (pgmname, (char *const *)argv);
+ /* No way to print anything, as we have may have closed all streams. */
+ _exit (127);
+}
+
+static gpg_err_code_t
+spawn_detached (gnupg_process_t process,
+ const char *pgmname, const char *argv[],
+ void (*spawn_cb) (struct spawn_cb_arg *), void *spawn_cb_arg)
+{
+ gpg_err_code_t ec;
+ pid_t pid;
+
+ /* FIXME: Is this GnuPG specific or should we keep it. */
+ if (getuid() != geteuid())
+ {
+ xfree (process);
+ xfree (argv);
+ return GPG_ERR_BUG;
+ }
+
+ if (access (pgmname, X_OK))
+ {
+ ec = gpg_err_code_from_syserror ();
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+
+ pre_syscall ();
+ pid = fork ();
+ post_syscall ();
+ if (pid == (pid_t)(-1))
+ {
+ ec = gpg_err_code_from_syserror ();
+ log_error (_("error forking process: %s\n"), gpg_strerror (ec));
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+
+ if (!pid)
+ {
+ pid_t pid2;
+ struct spawn_cb_arg sca;
+
+ if (setsid() == -1 || chdir ("/"))
+ _exit (1);
+
+ pid2 = fork (); /* Double fork to let init take over the new child. */
+ if (pid2 == (pid_t)(-1))
+ _exit (1);
+ if (pid2)
+ _exit (0); /* Let the parent exit immediately. */
+
+ call_spawn_cb (&sca, -1, -1, -1, spawn_cb, spawn_cb_arg);
+
+ my_exec (pgmname, argv, &sca);
+ /*NOTREACHED*/
+ }
+
+ pre_syscall ();
+ if (waitpid (pid, NULL, 0) == -1)
+ {
+ post_syscall ();
+ ec = gpg_err_code_from_syserror ();
+ log_error ("waitpid failed in gpgrt_spawn_process_detached: %s",
+ gpg_strerror (ec));
+ return ec;
+ }
+ else
+ post_syscall ();
+
+ process->pid = (pid_t)-1;
+ process->fd_in = -1;
+ process->fd_out = -1;
+ process->fd_err = -1;
+ process->wstatus = -1;
+ process->terminated = 1;
+ return 0;
+}
+
+void
+gnupg_spawn_helper (struct spawn_cb_arg *sca)
+{
+ int *user_except = sca->arg;
+#ifdef HAVE_W32_SYSTEM
+ if (user_except[0] == -1)
+ sca->ask_inherit = 0;
+ else
+ sca->ask_inherit = 1;
+#else
+ sca->except_fds = user_except;
+#endif
+}
+
+gpg_err_code_t
+gnupg_process_spawn (const char *pgmname, const char *argv1[],
+ unsigned int flags,
+ void (*spawn_cb) (struct spawn_cb_arg *),
+ void *spawn_cb_arg,
+ gnupg_process_t *r_process)
+{
+ gpg_err_code_t ec;
+ gnupg_process_t process;
+ int fd_in[2];
+ int fd_out[2];
+ int fd_err[2];
+ pid_t pid;
+ const char **argv;
+ int i, j;
+
+ check_syscall_func ();
+
+ if (r_process)
+ *r_process = NULL;
+
+ /* Create the command line argument array. */
+ i = 0;
+ if (argv1)
+ while (argv1[i])
+ i++;
+ argv = xtrycalloc (i+2, sizeof *argv);
+ if (!argv)
+ return gpg_err_code_from_syserror ();
+ argv[0] = strrchr (pgmname, '/');
+ if (argv[0])
+ argv[0]++;
+ else
+ argv[0] = pgmname;
+
+ if (argv1)
+ for (i=0, j=1; argv1[i]; i++, j++)
+ argv[j] = argv1[i];
+
+ process = xtrycalloc (1, sizeof (struct gnupg_process));
+ if (process == NULL)
+ {
+ xfree (argv);
+ return gpg_err_code_from_syserror ();
+ }
+
+ process->pgmname = pgmname;
+ process->flags = flags;
+
+ if ((flags & GNUPG_PROCESS_DETACHED))
+ {
+ if ((flags & GNUPG_PROCESS_STDFDS_SETTING))
+ {
+ xfree (process);
+ xfree (argv);
+ return GPG_ERR_INV_FLAG;
+ }
+
+ *r_process = process;
+ return spawn_detached (process, pgmname, argv, spawn_cb, spawn_cb_arg);
+ }
+
+ if ((flags & GNUPG_PROCESS_STDINOUT_SOCKETPAIR))
+ {
+ ec = do_create_socketpair (fd_in);
+ if (ec)
+ {
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+ fd_out[0] = dup (fd_in[0]);
+ fd_out[1] = dup (fd_in[1]);
+ }
+ else
+ {
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ {
+ ec = do_create_pipe (fd_in);
+ if (ec)
+ {
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDIN_NULL))
+ {
+ fd_in[0] = -1;
+ fd_in[1] = -1;
+ }
+ else
+ {
+ fd_in[0] = 0;
+ fd_in[1] = -1;
+ }
+
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ {
+ ec = do_create_pipe (fd_out);
+ if (ec)
+ {
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDOUT_NULL))
+ {
+ fd_out[0] = -1;
+ fd_out[1] = -1;
+ }
+ else
+ {
+ fd_out[0] = -1;
+ fd_out[1] = 1;
+ }
+ }
+
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ {
+ ec = do_create_pipe (fd_err);
+ if (ec)
+ {
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ if (fd_out[0] >= 0)
+ close (fd_out[0]);
+ if (fd_out[1] >= 0 && fd_out[1] != 1)
+ close (fd_out[1]);
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDERR_NULL))
+ {
+ fd_err[0] = -1;
+ fd_err[1] = -1;
+ }
+ else
+ {
+ fd_err[0] = -1;
+ fd_err[1] = 2;
+ }
+
+ pre_syscall ();
+ pid = fork ();
+ post_syscall ();
+ if (pid == (pid_t)(-1))
+ {
+ ec = gpg_err_code_from_syserror ();
+ log_error (_("error forking process: %s\n"), gpg_strerror (ec));
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ if (fd_out[0] >= 0)
+ close (fd_out[0]);
+ if (fd_out[1] >= 0 && fd_out[1] != 1)
+ close (fd_out[1]);
+ if (fd_err[0] >= 0)
+ close (fd_err[0]);
+ if (fd_err[1] >= 0 && fd_err[1] != 2)
+ close (fd_err[1]);
+ xfree (process);
+ xfree (argv);
+ return ec;
+ }
+
+ if (!pid)
+ {
+ struct spawn_cb_arg sca;
+
+ if (fd_in[1] >= 0)
+ close (fd_in[1]);
+ if (fd_out[0] >= 0)
+ close (fd_out[0]);
+ if (fd_err[0] >= 0)
+ close (fd_err[0]);
+
+ call_spawn_cb (&sca, fd_in[0], fd_out[1], fd_err[1],
+ spawn_cb, spawn_cb_arg);
+
+ /* Run child. */
+ my_exec (pgmname, argv, &sca);
+ /*NOTREACHED*/
+ }
+
+ xfree (argv);
+ process->pid = pid;
+
+ if (fd_in[0] >= 0 && fd_in[0] != 0)
+ close (fd_in[0]);
+ if (fd_out[1] >= 0 && fd_out[1] != 1)
+ close (fd_out[1]);
+ if (fd_err[1] >= 0 && fd_err[1] != 2)
+ close (fd_err[1]);
+ process->fd_in = fd_in[1];
+ process->fd_out = fd_out[0];
+ process->fd_err = fd_err[0];
+ process->wstatus = -1;
+ process->terminated = 0;
+
+ if (r_process == NULL)
+ {
+ ec = gnupg_process_wait (process, 1);
+ gnupg_process_release (process);
+ return ec;
+ }
+
+ *r_process = process;
+ return 0;
+}
+
+static gpg_err_code_t
+process_kill (gnupg_process_t process, int sig)
+{
+ gpg_err_code_t ec = 0;
+ pid_t pid = process->pid;
+
+ pre_syscall ();
+ if (kill (pid, sig) < 0)
+ ec = gpg_err_code_from_syserror ();
+ post_syscall ();
+ return ec;
+}
+
+gpg_err_code_t
+gnupg_process_terminate (gnupg_process_t process)
+{
+ return process_kill (process, SIGTERM);
+}
+
+gpg_err_code_t
+gnupg_process_get_fds (gnupg_process_t process, unsigned int flags,
+ int *r_fd_in, int *r_fd_out, int *r_fd_err)
+{
+ (void)flags;
+ if (r_fd_in)
+ {
+ *r_fd_in = process->fd_in;
+ process->fd_in = -1;
+ }
+ if (r_fd_out)
+ {
+ *r_fd_out = process->fd_out;
+ process->fd_out = -1;
+ }
+ if (r_fd_err)
+ {
+ *r_fd_err = process->fd_err;
+ process->fd_err = -1;
+ }
+
+ return 0;
+}
+
+gpg_err_code_t
+gnupg_process_get_streams (gnupg_process_t process, unsigned int flags,
+ gpgrt_stream_t *r_fp_in, gpgrt_stream_t *r_fp_out,
+ gpgrt_stream_t *r_fp_err)
+{
+ int nonblock = (flags & GNUPG_PROCESS_STREAM_NONBLOCK)? 1: 0;
+
+ if (r_fp_in)
+ {
+ *r_fp_in = es_fdopen (process->fd_in, nonblock? "w,nonblock" : "w");
+ process->fd_in = -1;
+ }
+ if (r_fp_out)
+ {
+ *r_fp_out = es_fdopen (process->fd_out, nonblock? "r,nonblock" : "r");
+ process->fd_out = -1;
+ }
+ if (r_fp_err)
+ {
+ *r_fp_err = es_fdopen (process->fd_err, nonblock? "r,nonblock" : "r");
+ process->fd_err = -1;
+ }
+ return 0;
+}
+
+static gpg_err_code_t
+process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr)
+{
+ switch (request)
+ {
+ case GNUPG_PROCESS_NOP:
+ return 0;
+
+ case GNUPG_PROCESS_GET_ID:
+ {
+ int *r_id = va_arg (arg_ptr, int *);
+
+ if (r_id == NULL)
+ return GPG_ERR_INV_VALUE;
+
+ *r_id = (int)process->pid;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_EXIT_ID:
+ {
+ int status = process->wstatus;
+ int *r_exit_status = va_arg (arg_ptr, int *);
+
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
+
+ if (WIFEXITED (status))
+ {
+ if (r_exit_status)
+ *r_exit_status = WEXITSTATUS (status);
+ }
+ else
+ *r_exit_status = -1;
+
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_PID:
+ {
+ pid_t *r_pid = va_arg (arg_ptr, pid_t *);
+
+ if (r_pid == NULL)
+ return GPG_ERR_INV_VALUE;
+
+ *r_pid = process->pid;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_WSTATUS:
+ {
+ int status = process->wstatus;
+ int *r_if_exited = va_arg (arg_ptr, int *);
+ int *r_if_signaled = va_arg (arg_ptr, int *);
+ int *r_exit_status = va_arg (arg_ptr, int *);
+ int *r_termsig = va_arg (arg_ptr, int *);
+
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
+
+ if (WIFEXITED (status))
+ {
+ if (r_if_exited)
+ *r_if_exited = 1;
+ if (r_if_signaled)
+ *r_if_signaled = 0;
+ if (r_exit_status)
+ *r_exit_status = WEXITSTATUS (status);
+ if (r_termsig)
+ *r_termsig = 0;
+ }
+ else if (WIFSIGNALED (status))
+ {
+ if (r_if_exited)
+ *r_if_exited = 0;
+ if (r_if_signaled)
+ *r_if_signaled = 1;
+ if (r_exit_status)
+ *r_exit_status = 0;
+ if (r_termsig)
+ *r_termsig = WTERMSIG (status);
+ }
+
+ return 0;
+ }
+
+ case GNUPG_PROCESS_KILL:
+ {
+ int sig = va_arg (arg_ptr, int);
+
+ return process_kill (process, sig);
+ }
+
+ default:
+ break;
+ }
+
+ return GPG_ERR_UNKNOWN_COMMAND;
+}
+
+gpg_err_code_t
+gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...)
+{
+ va_list arg_ptr;
+ gpg_err_code_t ec;
+
+ va_start (arg_ptr, request);
+ ec = process_vctl (process, request, arg_ptr);
+ va_end (arg_ptr);
+ return ec;
+}
+
+gpg_err_code_t
+gnupg_process_wait (gnupg_process_t process, int hang)
+{
+ gpg_err_code_t ec;
+ int status;
+ pid_t pid;
+
+ if (process->terminated)
+ /* Already terminated. */
+ return 0;
+
+ pre_syscall ();
+ while ((pid = waitpid (process->pid, &status, hang? 0: WNOHANG))
+ == (pid_t)(-1) && errno == EINTR);
+ post_syscall ();
+
+ if (pid == (pid_t)(-1))
+ {
+ ec = gpg_err_code_from_syserror ();
+ log_error (_("waiting for process %d to terminate failed: %s\n"),
+ (int)pid, gpg_strerror (ec));
+ }
+ else if (!pid)
+ {
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ }
+ else
+ {
+ process->terminated = 1;
+ process->wstatus = status;
+ ec = 0;
+ }
+
+ return ec;
+}
+
+void
+gnupg_process_release (gnupg_process_t process)
+{
+ if (!process)
+ return;
+
+ if (process->terminated)
+ {
+ gnupg_process_terminate (process);
+ gnupg_process_wait (process, 1);
+ }
+
+ xfree (process);
+}
+
+gpg_err_code_t
+gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang)
+{
+ gpg_err_code_t ec = 0;
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ if (process_list[i]->terminated)
+ continue;
+
+ ec = gnupg_process_wait (process_list[i], hang);
+ if (ec)
+ break;
+ }
+
+ return ec;
+}
diff --git a/common/exechelp-w32.c b/common/exechelp-w32.c
index 0034e03f2..219b7fe75 100644
--- a/common/exechelp-w32.c
+++ b/common/exechelp-w32.c
@@ -33,6 +33,8 @@
#if !defined(HAVE_W32_SYSTEM)
#error This code is only used on W32.
+#else
+#define _WIN32_WINNT 0x602
#endif
#include <stdio.h>
@@ -63,9 +65,11 @@
#include "util.h"
#include "i18n.h"
#include "sysutils.h"
+#define NEED_STRUCT_SPAWN_CB_ARG
#include "exechelp.h"
#include <windows.h>
+#include <processthreadsapi.h>
/* Define to 1 do enable debugging. */
#define DEBUG_W32_SPAWN 0
@@ -1048,3 +1052,756 @@ gnupg_kill_process (pid_t pid)
TerminateProcess (process, 1);
}
}
+
+struct gnupg_process {
+ const char *pgmname;
+ unsigned int terminated :1; /* or detached */
+ unsigned int flags;
+ HANDLE hProcess;
+ HANDLE hd_in;
+ HANDLE hd_out;
+ HANDLE hd_err;
+ int exitcode;
+};
+
+static int gnupg_process_syscall_func_initialized;
+
+/* Functions called before and after blocking syscalls. */
+static void (*pre_syscall_func) (void);
+static void (*post_syscall_func) (void);
+
+static void
+check_syscall_func (void)
+{
+ if (!gnupg_process_syscall_func_initialized)
+ {
+ gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
+ gnupg_process_syscall_func_initialized = 1;
+ }
+}
+
+static void
+pre_syscall (void)
+{
+ if (pre_syscall_func)
+ pre_syscall_func ();
+}
+
+static void
+post_syscall (void)
+{
+ if (post_syscall_func)
+ post_syscall_func ();
+}
+
+
+static gpg_err_code_t
+spawn_detached (gnupg_process_t process,
+ const char *pgmname, char *cmdline,
+ void (*spawn_cb) (struct spawn_cb_arg *), void *spawn_cb_arg)
+{
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
+ STARTUPINFOEXW si;
+ int cr_flags;
+ wchar_t *wcmdline = NULL;
+ wchar_t *wpgmname = NULL;
+ gpg_err_code_t ec;
+ int ret;
+ struct spawn_cb_arg sca;
+
+ ec = gnupg_access (pgmname, X_OK);
+ if (ec)
+ {
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+
+ memset (&si, 0, sizeof si);
+
+ sca.ask_inherit = FALSE;
+ sca.allow_foreground_window = FALSE;
+ sca.hd[0] = INVALID_HANDLE_VALUE;
+ sca.hd[1] = INVALID_HANDLE_VALUE;
+ sca.hd[2] = INVALID_HANDLE_VALUE;
+ sca.inherit_hds = NULL;
+ sca.arg = spawn_cb_arg;
+ if (spawn_cb)
+ (*spawn_cb) (&sca);
+
+ /* Prepare security attributes. */
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ /* Start the process. */
+ si.StartupInfo.cb = sizeof (si);
+ si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
+ si.StartupInfo.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
+
+ cr_flags = (CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_NEW_PROCESS_GROUP
+ | DETACHED_PROCESS);
+
+ /* Take care: CreateProcessW may modify wpgmname */
+ if (!(wpgmname = utf8_to_wchar (pgmname)))
+ ret = 0;
+ else if (!(wcmdline = utf8_to_wchar (cmdline)))
+ ret = 0;
+ else
+ ret = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ sca.ask_inherit, /* Inherit handles. */
+ cr_flags, /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ (STARTUPINFOW *)&si, /* Startup information. */
+ &pi /* Returns process information. */
+ );
+ if (!ret)
+ {
+ if (!wpgmname || !wcmdline)
+ log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
+ strerror (errno));
+ else
+ log_error ("CreateProcess(detached) failed: %d\n",
+ (int)GetLastError ());
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+ return GPG_ERR_GENERAL;
+ }
+ if (si.lpAttributeList)
+ DeleteProcThreadAttributeList (si.lpAttributeList);
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+
+ /* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ /* Note: AllowSetForegroundWindow doesn't make sense for background
+ process. */
+
+ CloseHandle (pi.hThread);
+ CloseHandle (pi.hProcess);
+
+ process->hProcess = INVALID_HANDLE_VALUE;
+ process->hd_in = INVALID_HANDLE_VALUE;
+ process->hd_out = INVALID_HANDLE_VALUE;
+ process->hd_err = INVALID_HANDLE_VALUE;
+ process->exitcode = -1;
+ process->terminated = 1;
+ return 0;
+}
+
+
+gpg_err_code_t
+gnupg_process_spawn (const char *pgmname, const char *argv[],
+ unsigned int flags,
+ void (*spawn_cb) (struct spawn_cb_arg *),
+ void *spawn_cb_arg,
+ gnupg_process_t *r_process)
+{
+ gpg_err_code_t ec;
+ gnupg_process_t process;
+ SECURITY_ATTRIBUTES sec_attr;
+ PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
+ STARTUPINFOEXW si;
+ int cr_flags;
+ char *cmdline;
+ wchar_t *wcmdline = NULL;
+ wchar_t *wpgmname = NULL;
+ int ret;
+ HANDLE hd_in[2];
+ HANDLE hd_out[2];
+ HANDLE hd_err[2];
+ struct spawn_cb_arg sca;
+ int i;
+
+ check_syscall_func ();
+
+ if (r_process)
+ *r_process = NULL;
+
+ /* Build the command line. */
+ ec = build_w32_commandline (pgmname, argv, &cmdline);
+ if (ec)
+ return ec;
+
+ process = xtrymalloc (sizeof (struct gnupg_process));
+ if (process == NULL)
+ {
+ xfree (cmdline);
+ return gpg_err_code_from_syserror ();
+ }
+
+ process->pgmname = pgmname;
+ process->flags = flags;
+
+ if ((flags & GNUPG_PROCESS_DETACHED))
+ {
+ if ((flags & GNUPG_PROCESS_STDFDS_SETTING))
+ {
+ xfree (process);
+ xfree (cmdline);
+ return GPG_ERR_INV_FLAG;
+ }
+
+ *r_process = process;
+ return spawn_detached (process, pgmname, cmdline, spawn_cb, spawn_cb_arg);
+ }
+
+ if ((flags & GNUPG_PROCESS_STDINOUT_SOCKETPAIR))
+ {
+ xfree (process);
+ xfree (cmdline);
+ return GPG_ERR_NOT_SUPPORTED;
+ }
+
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ {
+ ec = create_inheritable_pipe (hd_in, INHERIT_READ);
+ if (ec)
+ {
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDIN_NULL))
+ {
+ hd_in[0] = w32_open_null (0);
+ hd_in[1] = INVALID_HANDLE_VALUE;
+ }
+ else
+ {
+ hd_in[0] = GetStdHandle (STD_INPUT_HANDLE);
+ hd_in[1] = INVALID_HANDLE_VALUE;
+ }
+
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ {
+ ec = create_inheritable_pipe (hd_out, INHERIT_WRITE);
+ if (ec)
+ {
+ if (hd_in[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[0]);
+ if (hd_in[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[1]);
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDOUT_NULL))
+ {
+ hd_out[0] = INVALID_HANDLE_VALUE;
+ hd_out[1] = w32_open_null (1);
+ }
+ else
+ {
+ hd_out[0] = INVALID_HANDLE_VALUE;
+ hd_out[1] = GetStdHandle (STD_OUTPUT_HANDLE);
+ }
+
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ {
+ ec = create_inheritable_pipe (hd_err, INHERIT_WRITE);
+ if (ec)
+ {
+ if (hd_in[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[0]);
+ if (hd_in[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_in[1]);
+ if (hd_out[0] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_out[0]);
+ if (hd_out[1] != INVALID_HANDLE_VALUE)
+ CloseHandle (hd_out[1]);
+ xfree (process);
+ xfree (cmdline);
+ return ec;
+ }
+ }
+ else if ((flags & GNUPG_PROCESS_STDERR_NULL))
+ {
+ hd_err[0] = INVALID_HANDLE_VALUE;
+ hd_err[1] = w32_open_null (1);
+ }
+ else
+ {
+ hd_err[0] = INVALID_HANDLE_VALUE;
+ hd_err[1] = GetStdHandle (STD_ERROR_HANDLE);
+ }
+
+ memset (&si, 0, sizeof si);
+
+ sca.ask_inherit = FALSE;
+ sca.allow_foreground_window = FALSE;
+ sca.hd[0] = hd_in[0];
+ sca.hd[1] = hd_out[1];
+ sca.hd[2] = hd_err[1];
+ sca.inherit_hds = NULL;
+ sca.arg = spawn_cb_arg;
+ if (spawn_cb)
+ (*spawn_cb) (&sca);
+
+ i = 0;
+ if (sca.hd[0] != INVALID_HANDLE_VALUE)
+ i++;
+ if (sca.hd[1] != INVALID_HANDLE_VALUE)
+ i++;
+ if (sca.hd[2] != INVALID_HANDLE_VALUE)
+ i++;
+
+ if (i != 0 || sca.inherit_hds)
+ {
+ SIZE_T attr_list_size = 0;
+ HANDLE hd[16];
+ HANDLE *hd_p = sca.inherit_hds;
+ int j = 0;
+
+ if (sca.hd[0] != INVALID_HANDLE_VALUE)
+ hd[j++] = sca.hd[0];
+ if (sca.hd[1] != INVALID_HANDLE_VALUE)
+ hd[j++] = sca.hd[1];
+ if (sca.hd[1] != INVALID_HANDLE_VALUE)
+ hd[j++] = sca.hd[2];
+ if (hd_p)
+ {
+ while (*hd_p != INVALID_HANDLE_VALUE)
+ if (j < DIM (hd))
+ hd[j++] = *hd_p++;
+ else
+ {
+ log_error ("Too much handles\n");
+ break;
+ }
+ }
+
+ InitializeProcThreadAttributeList (NULL, 1, 0, &attr_list_size);
+ si.lpAttributeList = xtrymalloc (attr_list_size);
+ if (si.lpAttributeList == NULL)
+ {
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || (flags & GNUPG_PROCESS_STDIN_NULL))
+ CloseHandle (hd_in[0]);
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ CloseHandle (hd_in[1]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ CloseHandle (hd_out[0]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE)
+ || (flags & GNUPG_PROCESS_STDOUT_NULL))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ CloseHandle (hd_err[0]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || (flags & GNUPG_PROCESS_STDERR_NULL))
+ CloseHandle (hd_err[1]);
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (process);
+ xfree (cmdline);
+ return gpg_err_code_from_syserror ();
+ }
+ InitializeProcThreadAttributeList (si.lpAttributeList, 1, 0,
+ &attr_list_size);
+ UpdateProcThreadAttribute (si.lpAttributeList, 0,
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ hd, sizeof (HANDLE) * j, NULL, NULL);
+ sca.ask_inherit = TRUE;
+ }
+
+ /* Prepare security attributes. */
+ memset (&sec_attr, 0, sizeof sec_attr );
+ sec_attr.nLength = sizeof sec_attr;
+ sec_attr.bInheritHandle = FALSE;
+
+ /* Start the process. */
+ si.StartupInfo.cb = sizeof (si);
+ si.StartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+ si.StartupInfo.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE;
+ si.StartupInfo.hStdInput = sca.hd[0];
+ si.StartupInfo.hStdOutput = sca.hd[1];
+ si.StartupInfo.hStdError = sca.hd[2];
+
+ /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
+ cr_flags = (CREATE_DEFAULT_ERROR_MODE
+ | GetPriorityClass (GetCurrentProcess ())
+ | CREATE_SUSPENDED);
+ if (!(wpgmname = utf8_to_wchar (pgmname)))
+ ret = 0;
+ else if (!(wcmdline = utf8_to_wchar (cmdline)))
+ ret = 0;
+ else
+ ret = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ sca.ask_inherit, /* Inherit handles. */
+ cr_flags, /* Creation flags. */
+ NULL, /* Environment. */
+ NULL, /* Use current drive/directory. */
+ (STARTUPINFOW *)&si, /* Startup information. */
+ &pi /* Returns process information. */
+ );
+ if (!ret)
+ {
+ if (!wpgmname || !wcmdline)
+ log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
+ strerror (errno));
+ else
+ log_error ("CreateProcess failed: ec=%d\n",
+ (int)GetLastError ());
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || (flags & GNUPG_PROCESS_STDIN_NULL))
+ CloseHandle (hd_in[0]);
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE))
+ CloseHandle (hd_in[1]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE))
+ CloseHandle (hd_out[0]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE)
+ || (flags & GNUPG_PROCESS_STDOUT_NULL))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ CloseHandle (hd_err[0]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || (flags & GNUPG_PROCESS_STDERR_NULL))
+ CloseHandle (hd_err[1]);
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (process);
+ xfree (cmdline);
+ return GPG_ERR_GENERAL;
+ }
+
+ if (si.lpAttributeList)
+ DeleteProcThreadAttributeList (si.lpAttributeList);
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (cmdline);
+
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || (flags & GNUPG_PROCESS_STDIN_NULL))
+ CloseHandle (hd_in[0]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE)
+ || (flags & GNUPG_PROCESS_STDOUT_NULL))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || (flags & GNUPG_PROCESS_STDERR_NULL))
+ CloseHandle (hd_err[1]);
+
+ /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+
+ if (sca.allow_foreground_window)
+ {
+ /* Fixme: For unknown reasons AllowSetForegroundWindow returns
+ * an invalid argument error if we pass it the correct
+ * processID. As a workaround we use -1 (ASFW_ANY). */
+ if (!AllowSetForegroundWindow (ASFW_ANY /*pi.dwProcessId*/))
+ log_info ("AllowSetForegroundWindow() failed: ec=%d\n",
+ (int)GetLastError ());
+ }
+
+ /* Process has been created suspended; resume it now. */
+ pre_syscall ();
+ ResumeThread (pi.hThread);
+ CloseHandle (pi.hThread);
+ post_syscall ();
+
+ process->hProcess = pi.hProcess;
+ process->hd_in = hd_in[1];
+ process->hd_out = hd_out[0];
+ process->hd_err = hd_err[0];
+ process->exitcode = -1;
+ process->terminated = 0;
+
+ if (r_process == NULL)
+ {
+ ec = gnupg_process_wait (process, 1);
+ gnupg_process_release (process);
+ return ec;
+ }
+
+ *r_process = process;
+ return 0;
+}
+
+gpg_err_code_t
+gnupg_process_get_fds (gnupg_process_t process, unsigned int flags,
+ int *r_fd_in, int *r_fd_out, int *r_fd_err)
+{
+ (void)flags;
+ if (r_fd_in)
+ {
+ *r_fd_in = _open_osfhandle ((intptr_t)process->hd_in, O_APPEND);
+ process->hd_in = INVALID_HANDLE_VALUE;
+ }
+ if (r_fd_out)
+ {
+ *r_fd_out = _open_osfhandle ((intptr_t)process->hd_out, O_RDONLY);
+ process->hd_out = INVALID_HANDLE_VALUE;
+ }
+ if (r_fd_err)
+ {
+ *r_fd_err = _open_osfhandle ((intptr_t)process->hd_err, O_RDONLY);
+ process->hd_err = INVALID_HANDLE_VALUE;
+ }
+
+ return 0;
+}
+
+gpg_err_code_t
+gnupg_process_get_streams (gnupg_process_t process, unsigned int flags,
+ estream_t *r_fp_in, estream_t *r_fp_out,
+ estream_t *r_fp_err)
+{
+ int nonblock = (flags & GNUPG_PROCESS_STREAM_NONBLOCK)? 1: 0;
+ es_syshd_t syshd;
+
+ syshd.type = ES_SYSHD_HANDLE;
+ if (r_fp_in)
+ {
+ syshd.u.handle = process->hd_in;
+ *r_fp_in = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
+ process->hd_in = INVALID_HANDLE_VALUE;
+ }
+ if (r_fp_out)
+ {
+ syshd.u.handle = process->hd_out;
+ *r_fp_out = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+ process->hd_out = INVALID_HANDLE_VALUE;
+ }
+ if (r_fp_err)
+ {
+ syshd.u.handle = process->hd_err;
+ *r_fp_err = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
+ process->hd_err = INVALID_HANDLE_VALUE;
+ }
+ return 0;
+}
+
+static gpg_err_code_t
+process_kill (gnupg_process_t process, unsigned int exitcode)
+{
+ gpg_err_code_t ec = 0;
+
+ pre_syscall ();
+ if (TerminateProcess (process->hProcess, exitcode))
+ ec = gpg_err_code_from_syserror ();
+ post_syscall ();
+ return ec;
+}
+
+static gpg_err_code_t
+process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr)
+{
+ switch (request)
+ {
+ case GNUPG_PROCESS_NOP:
+ return 0;
+
+ case GNUPG_PROCESS_GET_ID:
+ {
+ int *r_id = va_arg (arg_ptr, int *);
+
+ if (r_id == NULL)
+ return GPG_ERR_INV_VALUE;
+
+ *r_id = (int)process->hProcess;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_EXIT_ID:
+ {
+ int *r_exit_status = va_arg (arg_ptr, int *);
+ unsigned long exit_code;
+
+ *r_exit_status = -1;
+
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
+
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ return 0;
+
+ if (GetExitCodeProcess (process->hProcess, &exit_code) == 0)
+ return gpg_err_code_from_syserror ();
+
+ *r_exit_status = (int)exit_code;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_P_HANDLE:
+ {
+ HANDLE *r_hProcess = va_arg (arg_ptr, HANDLE *);
+
+ if (r_hProcess == NULL)
+ return GPG_ERR_INV_VALUE;
+
+ *r_hProcess = process->hProcess;
+ process->hProcess = INVALID_HANDLE_VALUE;
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_HANDLES:
+ {
+ HANDLE *r_hd_in = va_arg (arg_ptr, HANDLE *);
+ HANDLE *r_hd_out = va_arg (arg_ptr, HANDLE *);
+ HANDLE *r_hd_err = va_arg (arg_ptr, HANDLE *);
+
+ if (r_hd_in)
+ {
+ *r_hd_in = process->hd_in;
+ process->hd_in = INVALID_HANDLE_VALUE;
+ }
+ if (r_hd_out)
+ {
+ *r_hd_out = process->hd_out;
+ process->hd_out = INVALID_HANDLE_VALUE;
+ }
+ if (r_hd_err)
+ {
+ *r_hd_err = process->hd_err;
+ process->hd_err = INVALID_HANDLE_VALUE;
+ }
+ return 0;
+ }
+
+ case GNUPG_PROCESS_GET_EXIT_CODE:
+ {
+ unsigned long *r_exitcode = va_arg (arg_ptr, unsigned long *);
+
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
+
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ {
+ *r_exitcode = (unsigned long)-1;
+ return 0;
+ }
+
+ if (GetExitCodeProcess (process->hProcess, r_exitcode) == 0)
+ return gpg_err_code_from_syserror ();
+ return 0;
+ }
+
+ case GNUPG_PROCESS_KILL_WITH_EC:
+ {
+ unsigned int exitcode = va_arg (arg_ptr, unsigned int);
+
+ if (process->terminated)
+ return 0;
+
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ return 0;
+
+ return process_kill (process, exitcode);
+ }
+
+ default:
+ break;
+ }
+
+ return GPG_ERR_UNKNOWN_COMMAND;
+}
+
+gpg_err_code_t
+gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...)
+{
+ va_list arg_ptr;
+ gpg_err_code_t ec;
+
+ va_start (arg_ptr, request);
+ ec = process_vctl (process, request, arg_ptr);
+ va_end (arg_ptr);
+ return ec;
+}
+
+gpg_err_code_t
+gnupg_process_wait (gnupg_process_t process, int hang)
+{
+ gpg_err_code_t ec;
+ int code;
+
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ return 0;
+
+ pre_syscall ();
+ code = WaitForSingleObject (process->hProcess, hang? INFINITE : 0);
+ post_syscall ();
+
+ switch (code)
+ {
+ case WAIT_TIMEOUT:
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ break;
+
+ case WAIT_FAILED:
+ log_error (_("waiting for process to terminate failed: ec=%d\n"),
+ (int)GetLastError ());
+ ec = GPG_ERR_GENERAL;
+ break;
+
+ case WAIT_OBJECT_0:
+ process->terminated = 1;
+ ec = 0;
+ break;
+
+ default:
+ log_debug ("WaitForSingleObject returned unexpected code %d\n", code);
+ ec = GPG_ERR_GENERAL;
+ break;
+ }
+
+ return ec;
+}
+
+gpg_err_code_t
+gnupg_process_terminate (gnupg_process_t process)
+{
+ return process_kill (process, 1);
+}
+
+void
+gnupg_process_release (gnupg_process_t process)
+{
+ if (!process)
+ return;
+
+ if (process->terminated)
+ {
+ gnupg_process_terminate (process);
+ gnupg_process_wait (process, 1);
+ }
+
+ xfree (process);
+}
+
+gpg_err_code_t
+gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang)
+{
+ gpg_err_code_t ec = 0;
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ if (process_list[i]->terminated)
+ continue;
+
+ ec = gnupg_process_wait (process_list[i], hang);
+ if (ec)
+ break;
+ }
+
+ return ec;
+}
diff --git a/common/exechelp.h b/common/exechelp.h
index 3343fe598..cd91d3e39 100644
--- a/common/exechelp.h
+++ b/common/exechelp.h
@@ -207,6 +207,108 @@ gpg_error_t gnupg_spawn_process_detached (const char *pgmname,
const char *argv[],
const char *envp[] );
+
+/* The opaque type for a subprocess. */
+typedef struct gnupg_process *gnupg_process_t;
+#ifdef HAVE_W32_SYSTEM
+struct spawn_cb_arg;
+#ifdef NEED_STRUCT_SPAWN_CB_ARG
+struct spawn_cb_arg {
+ HANDLE hd[3];
+ HANDLE *inherit_hds;
+ BOOL ask_inherit;
+ BOOL allow_foreground_window;
+ void *arg;
+};
+#endif
+#else
+struct spawn_cb_arg {
+ int fds[3];
+ int *except_fds;
+ void *arg;
+};
+#endif
+
+/* Internal flag to ihnerit file descriptor/handle */
+#define GNUPG_PROCESS_INHERIT_FILE (1 << 0)
+
+#define GNUPG_PROCESS_DETACHED (1 << 1)
+
+/* Specify how to keep/connect standard fds. */
+#define GNUPG_PROCESS_STDIN_PIPE (1 << 8)
+#define GNUPG_PROCESS_STDOUT_PIPE (1 << 9)
+#define GNUPG_PROCESS_STDERR_PIPE (1 << 10)
+#define GNUPG_PROCESS_STDINOUT_SOCKETPAIR (1 << 11)
+#define GNUPG_PROCESS_STDIN_NULL (1 << 12)
+#define GNUPG_PROCESS_STDOUT_NULL (1 << 13)
+#define GNUPG_PROCESS_STDERR_NULL (1 << 14)
+#define GNUPG_PROCESS_STDFDS_SETTING ( GNUPG_PROCESS_STDIN_PIPE \
+ | GNUPG_PROCESS_STDOUT_PIPE | GNUPG_PROCESS_STDERR_PIPE \
+ | GNUPG_PROCESS_STDINOUT_SOCKETPAIR | GNUPG_PROCESS_STDIN_NULL \
+ | GNUPG_PROCESS_STDOUT_NULL | GNUPG_PROCESS_STDERR_NULL)
+
+#define GNUPG_PROCESS_STREAM_NONBLOCK (1 << 16)
+
+/* Spawn helper. */
+void gnupg_spawn_helper (struct spawn_cb_arg *sca);
+
+/* Spawn PGMNAME. */
+gpg_err_code_t gnupg_process_spawn (const char *pgmname, const char *argv[],
+ unsigned int flags,
+ void (*spawn_cb) (struct spawn_cb_arg *),
+ void *spawn_cb_arg,
+ gnupg_process_t *r_process);
+
+/* Get FDs for subprocess I/O. It is the caller which should care
+ FDs (closing FDs). */
+gpg_err_code_t gnupg_process_get_fds (gnupg_process_t process,
+ unsigned int flags,
+ int *r_fd_in, int *r_fd_out,
+ int *r_fd_err);
+
+/* Get STREAMs for subprocess I/O. It is the caller which should care
+ STREAMs (closing STREAMs). */
+gpg_err_code_t gnupg_process_get_streams (gnupg_process_t process,
+ unsigned int flags,
+ gpgrt_stream_t *r_fp_in,
+ gpgrt_stream_t *r_fp_out,
+ gpgrt_stream_t *r_fp_err);
+
+enum gnupg_process_requests
+ {
+ /* Portable requests */
+ GNUPG_PROCESS_NOP = 0,
+ GNUPG_PROCESS_GET_ID = 1,
+ GNUPG_PROCESS_GET_EXIT_ID = 2,
+
+ /* POSIX only */
+ GNUPG_PROCESS_GET_PID = 16,
+ GNUPG_PROCESS_GET_WSTATUS = 17,
+ GNUPG_PROCESS_KILL = 18,
+
+ /* Windows only */
+ GNUPG_PROCESS_GET_P_HANDLE = 32,
+ GNUPG_PROCESS_GET_HANDLES = 33,
+ GNUPG_PROCESS_GET_EXIT_CODE = 34,
+ GNUPG_PROCESS_KILL_WITH_EC = 35
+ };
+
+/* Control of a process. */
+gpg_err_code_t gnupg_process_ctl (gnupg_process_t process,
+ unsigned int request, ...);
+
+/* Wait for a single PROCESS. */
+gpg_err_code_t gnupg_process_wait (gnupg_process_t process, int hang);
+
+/* Terminate a PROCESS. */
+gpg_err_code_t gnupg_process_terminate (gnupg_process_t process);
+
+/* Release PROCESS resources. */
+void gnupg_process_release (gnupg_process_t process);
+
+/* Wait for a multiple processes. */
+gpg_err_code_t gnupg_process_wait_list (gnupg_process_t *process_list,
+ int count, int hang);
#endif /*GNUPG_COMMON_EXECHELP_H*/
diff --git a/common/exectool.c b/common/exectool.c
index aaf5898d0..9a8e61c20 100644
--- a/common/exectool.c
+++ b/common/exectool.c
@@ -38,10 +38,14 @@
#include <gpg-error.h>
#include <assuan.h>
+
#include "i18n.h"
#include "logging.h"
#include "membuf.h"
#include "mischelp.h"
+#ifdef HAVE_W32_SYSTEM
+#define NEED_STRUCT_SPAWN_CB_ARG 1
+#endif
#include "exechelp.h"
#include "sysutils.h"
#include "util.h"
@@ -301,7 +305,6 @@ copy_buffer_flush (struct copy_buffer *c, estream_t sink)
}
-
/* Run the program PGMNAME with the command line arguments given in
* the NULL terminates array ARGV. If INPUT is not NULL it will be
* fed to stdin of the process. stderr is logged using log_info and
@@ -321,7 +324,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
void *status_cb_value)
{
gpg_error_t err;
- pid_t pid = (pid_t) -1;
+ gnupg_process_t proc = NULL;
estream_t infp = NULL;
estream_t extrafp = NULL;
estream_t outfp = NULL, errfp = NULL;
@@ -335,7 +338,6 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
read_and_log_buffer_t fderrstate;
struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
int quiet = 0;
- int dummy_exitcode;
memset (fds, 0, sizeof fds);
memset (&fderrstate, 0, sizeof fderrstate);
@@ -411,10 +413,15 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
else
exceptclose[0] = -1;
- err = gnupg_spawn_process (pgmname, argv,
- exceptclose, GNUPG_SPAWN_NONBLOCK,
- input? &infp : NULL,
- &outfp, &errfp, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ ((input
+ ? GNUPG_PROCESS_STDIN_PIPE
+ : GNUPG_PROCESS_STDIN_NULL)
+ | GNUPG_PROCESS_STDOUT_PIPE
+ | GNUPG_PROCESS_STDERR_PIPE),
+ gnupg_spawn_helper, exceptclose, &proc);
+ gnupg_process_get_streams (proc, GNUPG_PROCESS_STREAM_NONBLOCK,
+ input? &infp : NULL, &outfp, &errfp);
if (extrapipe[0] != -1)
close (extrapipe[0]);
if (argsave)
@@ -546,20 +553,25 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
es_fclose (outfp); outfp = NULL;
es_fclose (errfp); errfp = NULL;
- err = gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
- pid = (pid_t)(-1);
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
+ { /* To be compatible to old wait_process. */
+ int status;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
+ if (status)
+ err = gpg_error (GPG_ERR_GENERAL);
+ }
leave:
- if (err && pid != (pid_t) -1)
- gnupg_kill_process (pid);
+ if (err && proc)
+ gnupg_process_terminate (proc);
es_fclose (infp);
es_fclose (extrafp);
es_fclose (outfp);
es_fclose (errfp);
- if (pid != (pid_t)(-1))
- gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
copy_buffer_shred (cpbuf_in);
xfree (cpbuf_in);
diff --git a/dirmngr/ldap-wrapper.c b/dirmngr/ldap-wrapper.c
index 23d514cf9..096642fda 100644
--- a/dirmngr/ldap-wrapper.c
+++ b/dirmngr/ldap-wrapper.c
@@ -87,7 +87,7 @@ struct wrapper_context_s
{
struct wrapper_context_s *next;
- pid_t pid; /* The pid of the wrapper process. */
+ gnupg_process_t proc;/* The wrapper process. */
int printable_pid; /* Helper to print diagnostics after the process has
* been cleaned up. */
estream_t fp; /* Connected with stdout of the ldap wrapper. */
@@ -170,10 +170,10 @@ read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
static void
destroy_wrapper (struct wrapper_context_s *ctx)
{
- if (ctx->pid != (pid_t)(-1))
+ if (ctx->proc)
{
- gnupg_kill_process (ctx->pid);
- gnupg_release_process (ctx->pid);
+ gnupg_process_terminate (ctx->proc);
+ gnupg_process_release (ctx->proc);
}
ksba_reader_release (ctx->reader);
SAFE_CLOSE (ctx->fp);
@@ -260,7 +260,7 @@ read_log_data (struct wrapper_context_s *ctx)
if (gpg_err_code (err) == GPG_ERR_EAGAIN)
return 0;
log_error (_("error reading log from ldap wrapper %d: %s\n"),
- (int)ctx->pid, gpg_strerror (err));
+ (int)ctx->printable_pid, gpg_strerror (err));
}
print_log_line (ctx, NULL); /* Flush. */
SAFE_CLOSE (ctx->log_fp);
@@ -438,50 +438,44 @@ ldap_reaper_thread (void *dummy)
}
/* Check whether the process is still running. */
- if (ctx->pid != (pid_t)(-1))
+ if (ctx->proc)
{
- int status;
-
- err = gnupg_wait_process ("[dirmngr_ldap]", ctx->pid, 0,
- &status);
+ err = gnupg_process_wait (ctx->proc, 0);
if (!err)
{
+ int status;
+
+ gnupg_process_ctl (ctx->proc,
+ GNUPG_PROCESS_GET_EXIT_ID, &status);
if (DBG_EXTPROG)
- log_info (_("ldap wrapper %d ready"), (int)ctx->pid);
+ log_info (_("ldap wrapper %d ready"), (int)ctx->printable_pid);
ctx->ready = 1;
- gnupg_release_process (ctx->pid);
- ctx->pid = (pid_t)(-1);
+ gnupg_process_release (ctx->proc);
+ ctx->proc = NULL;
any_action = 1;
- }
- else if (gpg_err_code (err) == GPG_ERR_GENERAL)
- {
+
if (status == 10)
log_info (_("ldap wrapper %d ready: timeout\n"),
- (int)ctx->pid);
+ (int)ctx->printable_pid);
else
log_info (_("ldap wrapper %d ready: exitcode=%d\n"),
- (int)ctx->pid, status);
- ctx->ready = 1;
- gnupg_release_process (ctx->pid);
- ctx->pid = (pid_t)(-1);
- any_action = 1;
+ (int)ctx->printable_pid, status);
}
else if (gpg_err_code (err) != GPG_ERR_TIMEOUT)
{
log_error (_("waiting for ldap wrapper %d failed: %s\n"),
- (int)ctx->pid, gpg_strerror (err));
+ (int)ctx->printable_pid, gpg_strerror (err));
any_action = 1;
}
}
/* Check whether we should terminate the process. */
- if (ctx->pid != (pid_t)(-1)
- && ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
+ if (ctx->proc && ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
{
- gnupg_kill_process (ctx->pid);
+ gnupg_process_terminate (ctx->proc);
ctx->stamp = (time_t)(-1);
log_info (_("ldap wrapper %d stalled - killing\n"),
- (int)ctx->pid);
+ (int)ctx->printable_pid);
/* We need to close the log stream because the cleanup
* loop waits for it. */
SAFE_CLOSE (ctx->log_fp);
@@ -496,10 +490,10 @@ ldap_reaper_thread (void *dummy)
{
log_debug ("ldap worker states:\n");
for (ctx = reaper_list; ctx; ctx = ctx->next)
- log_debug (" c=%p pid=%d/%d rdr=%p logfp=%p"
+ log_debug (" c=%p pid=%d rdr=%p logfp=%p"
" ctrl=%p/%d la=%lu rdy=%d\n",
ctx,
- (int)ctx->pid, (int)ctx->printable_pid,
+ (int)ctx->printable_pid,
ctx->reader, ctx->log_fp,
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0,
(unsigned long)ctx->stamp, ctx->ready);
@@ -602,9 +596,9 @@ ldap_wrapper_release_context (ksba_reader_t reader)
if (ctx->reader == reader)
{
if (DBG_EXTPROG)
- log_debug ("releasing ldap worker c=%p pid=%d/%d rdr=%p"
+ log_debug ("releasing ldap worker c=%p pid=%d rdr=%p"
" ctrl=%p/%d\n", ctx,
- (int)ctx->pid, (int)ctx->printable_pid,
+ (int)ctx->printable_pid,
ctx->reader,
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
@@ -639,8 +633,8 @@ ldap_wrapper_connection_cleanup (ctrl_t ctrl)
{
ctx->ctrl->refcount--;
ctx->ctrl = NULL;
- if (ctx->pid != (pid_t)(-1))
- gnupg_kill_process (ctx->pid);
+ if (ctx->proc)
+ gnupg_process_terminate (ctx->proc);
if (ctx->fp_err)
log_info ("%s: reading from ldap wrapper %d failed: %s\n",
__func__, ctx->printable_pid, gpg_strerror (ctx->fp_err));
@@ -798,7 +792,7 @@ gpg_error_t
ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
{
gpg_error_t err;
- pid_t pid;
+ gnupg_process_t process;
struct wrapper_context_s *ctx;
int i;
int j;
@@ -854,19 +848,23 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
return err;
}
- err = gnupg_spawn_process (pgmname, arg_list,
- NULL, GNUPG_SPAWN_NONBLOCK,
- NULL, &outfp, &errfp, &pid);
+ err = gnupg_process_spawn (pgmname, arg_list,
+ (GNUPG_PROCESS_STDIN_NULL
+ | GNUPG_PROCESS_STDOUT_PIPE
+ | GNUPG_PROCESS_STDERR_PIPE),
+ NULL, NULL, &process);
if (err)
{
- xfree (arg_list);
+ xfree (arg_list);
xfree (ctx);
log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
return err;
}
+ gnupg_process_get_streams (process, GNUPG_PROCESS_STREAM_NONBLOCK,
+ NULL, &outfp, &errfp);
+ gnupg_process_ctl (process, GNUPG_PROCESS_GET_ID, &ctx->printable_pid);
- ctx->pid = pid;
- ctx->printable_pid = (int) pid;
+ ctx->proc = process;
ctx->fp = outfp;
ctx->log_fp = errfp;
ctx->ctrl = ctrl;
@@ -902,7 +900,7 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
if (DBG_EXTPROG)
{
log_debug ("ldap wrapper %d started (%p, %s)",
- (int)ctx->pid, ctx->reader, pgmname);
+ (int)ctx->printable_pid, ctx->reader, pgmname);
for (i=0; arg_list[i]; i++)
log_printf (" [%s]", arg_list[i]);
log_printf ("\n");
diff --git a/g10/photoid.c b/g10/photoid.c
index 72e6acf7d..6f04f5ea2 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -594,34 +594,37 @@ run_with_pipe (struct spawn_info *info, const void *image, u32 len)
" external programs\n"));
return;
#else /* !EXEC_TEMPFILE_ONLY */
- int to[2];
- pid_t pid;
gpg_error_t err;
const char *argv[4];
-
- err = gnupg_create_pipe (to);
- if (err)
- return;
+ gnupg_process_t proc;
fill_command_argv (argv, info->command);
- err = gnupg_spawn_process_fd (argv[0], argv+1, to[0], -1, -1, &pid);
-
- close (to[0]);
-
+ err = gnupg_process_spawn (argv[0], argv+1,
+ (GNUPG_PROCESS_STDIN_PIPE | GNUPG_PROCESS_STDOUT_NULL
+ | GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (err)
- {
- log_error (_("unable to execute shell '%s': %s\n"),
- argv[0], gpg_strerror (err));
- close (to[1]);
- }
+ log_error (_("unable to execute shell '%s': %s\n"),
+ argv[0], gpg_strerror (err));
else
{
- write (to[1], image, len);
- close (to[1]);
+ int fd_in;
- err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ err = gnupg_process_get_fds (proc, 0, &fd_in, NULL, NULL);
+ if (err)
+ log_error ("unable to get pipe connection '%s': %s\n",
+ argv[2], gpg_strerror (err));
+ else
+ {
+ write (fd_in, image, len);
+ close (fd_in);
+ }
+
+ err = gnupg_process_wait (proc, 1);
if (err)
log_error (_("unnatural exit of external program\n"));
+
+ gnupg_process_release (proc);
}
#endif /* !EXEC_TEMPFILE_ONLY */
}
@@ -689,14 +692,15 @@ show_photo (const char *command, const char *name, const void *image, u32 len)
log_error (_("system error while calling external program: %s\n"),
strerror (errno));
#else
- pid_t pid;
gpg_error_t err;
const char *argv[4];
fill_command_argv (argv, spawn->command);
- err = gnupg_spawn_process_fd (argv[0], argv+1, -1, -1, -1, &pid);
- if (!err)
- err = gnupg_wait_process (argv[0], pid, 1, NULL);
+ err = gnupg_process_spawn (argv[0], argv+1,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, NULL);
if (err)
log_error (_("unnatural exit of external program\n"));
#endif
diff --git a/g13/be-encfs.c b/g13/be-encfs.c
index 0e2c68bf3..9adb1e092 100644
--- a/g13/be-encfs.c
+++ b/g13/be-encfs.c
@@ -28,10 +28,10 @@
#include "g13.h"
#include "../common/i18n.h"
#include "keyblob.h"
-#include "be-encfs.h"
-#include "runner.h"
#include "../common/sysutils.h"
#include "../common/exechelp.h"
+#include "runner.h"
+#include "be-encfs.h"
/* Command values used to run the encfs tool. */
@@ -81,7 +81,11 @@ run_umount_helper (const char *mountpoint)
args[1] = mountpoint;
args[2] = NULL;
- err = gnupg_spawn_process_detached (pgmname, args, NULL);
+ err = gnupg_process_spawn (pgmname, args,
+ (GNUPG_PROCESS_DETACHED | GNUPG_PROCESS_STDIN_NULL
+ | GNUPG_PROCESS_STDOUT_NULL
+ | GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, NULL);
if (err)
log_error ("failed to run '%s': %s\n",
pgmname, gpg_strerror (err));
@@ -218,12 +222,11 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
gpg_error_t err;
encfs_parm_t parm;
runner_t runner = NULL;
- int outbound[2] = { -1, -1 };
- int inbound[2] = { -1, -1 };
const char *pgmname;
const char *argv[10];
- pid_t pid = (pid_t)(-1);
int idx;
+ gnupg_process_t proc;
+ int inbound, outbound;
(void)ctrl;
@@ -246,15 +249,6 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
if (err)
goto leave;
- err = gnupg_create_inbound_pipe (inbound, NULL, 0);
- if (!err)
- err = gnupg_create_outbound_pipe (outbound, NULL, 0);
- if (err)
- {
- log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
- goto leave;
- }
-
pgmname = ENCFS;
idx = 0;
argv[idx++] = "-f";
@@ -267,47 +261,42 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
argv[idx++] = NULL;
assert (idx <= DIM (argv));
- err = gnupg_spawn_process_fd (pgmname, argv,
- outbound[0], -1, inbound[1], &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_PIPE | GNUPG_PROCESS_STDOUT_NULL
+ | GNUPG_PROCESS_STDERR_PIPE),
+ NULL, NULL, &proc);
if (err)
{
log_error ("error spawning '%s': %s\n", pgmname, gpg_strerror (err));
goto leave;
}
- close (outbound[0]); outbound[0] = -1;
- close ( inbound[1]); inbound[1] = -1;
- runner_set_fds (runner, inbound[0], outbound[1]);
- inbound[0] = -1; /* Now owned by RUNNER. */
- outbound[1] = -1; /* Now owned by RUNNER. */
+ err = gnupg_process_get_fds (proc, 0, &outbound, NULL, &inbound);
+ if (err)
+ {
+ log_error ("error get fds '%s': %s\n", pgmname, gpg_strerror (err));
+ gnupg_process_release (proc);
+ goto leave;
+ }
+
+ runner_set_fds (runner, inbound, outbound);
runner_set_handler (runner, encfs_handler, encfs_handler_cleanup, parm);
parm = NULL; /* Now owned by RUNNER. */
- runner_set_pid (runner, pid);
- pid = (pid_t)(-1); /* The process is now owned by RUNNER. */
+ runner_set_proc (runner, proc);
err = runner_spawn (runner);
if (err)
- goto leave;
+ {
+ gnupg_process_release (proc);
+ goto leave;
+ }
*r_id = runner_get_rid (runner);
log_info ("running '%s' in the background\n", pgmname);
leave:
- if (inbound[0] != -1)
- close (inbound[0]);
- if (inbound[1] != -1)
- close (inbound[1]);
- if (outbound[0] != -1)
- close (outbound[0]);
- if (outbound[1] != -1)
- close (outbound[1]);
- if (pid != (pid_t)(-1))
- {
- gnupg_wait_process (pgmname, pid, 1, NULL);
- gnupg_release_process (pid);
- }
runner_release (runner);
encfs_handler_cleanup (parm);
return err;
diff --git a/g13/g13.c b/g13/g13.c
index 2bbb453eb..785c91950 100644
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -40,6 +40,7 @@
#include "../common/gc-opt-flags.h"
#include "../common/asshelp.h"
#include "../common/init.h"
+#include "../common/exechelp.h"
#include "keyblob.h"
#include "server.h"
#include "runner.h"
diff --git a/g13/mount.c b/g13/mount.c
index 45b60806c..071b76b67 100644
--- a/g13/mount.c
+++ b/g13/mount.c
@@ -34,10 +34,11 @@
#include "backend.h"
#include "g13tuple.h"
#include "mountinfo.h"
-#include "runner.h"
#include "../common/host2net.h"
#include "server.h" /*(g13_keyblob_decrypt)*/
#include "../common/sysutils.h"
+#include "../common/exechelp.h"
+#include "runner.h"
#include "call-syshelp.h"
diff --git a/g13/runner.c b/g13/runner.c
index b08d99030..c0534fe5d 100644
--- a/g13/runner.c
+++ b/g13/runner.c
@@ -29,8 +29,8 @@
#include "g13.h"
#include "../common/i18n.h"
#include "keyblob.h"
-#include "runner.h"
#include "../common/exechelp.h"
+#include "runner.h"
#include "mountinfo.h"
/* The runner object. */
@@ -55,7 +55,7 @@ struct runner_s
2 = Thread is running and someone is holding a reference. */
int refcount;
- pid_t pid; /* PID of the backend's process (the engine). */
+ gnupg_process_t proc; /* Process of the backend's process (the engine). */
int in_fd; /* File descriptors to read from the engine. */
int out_fd; /* File descriptors to write to the engine. */
engine_handler_fnc_t handler; /* The handler functions. */
@@ -157,16 +157,16 @@ runner_release (runner_t runner)
if (runner->handler_cleanup)
runner->handler_cleanup (runner->handler_data);
- if (runner->pid != (pid_t)(-1))
+ if (runner->proc)
{
/* The process has not been cleaned up - do it now. */
- gnupg_kill_process (runner->pid);
+ gnupg_process_terminate (runner->proc);
/* (Actually we should use the program name and not the
arbitrary NAME of the runner object. However it does not
matter because that information is only used for
diagnostics.) */
- gnupg_wait_process (runner->name, runner->pid, 1, NULL);
- gnupg_release_process (runner->pid);
+ gnupg_process_wait (runner->proc, 1);
+ gnupg_process_release (runner->proc);
}
xfree (runner->name);
@@ -212,7 +212,7 @@ runner_new (runner_t *r_runner, const char *name)
return gpg_error_from_syserror ();
}
runner->refcount = 1;
- runner->pid = (pid_t)(-1);
+ runner->proc = NULL;
runner->in_fd = -1;
runner->out_fd = -1;
@@ -266,15 +266,15 @@ runner_set_fds (runner_t runner, int in_fd, int out_fd)
}
-/* Set the PID of the backend engine. After this call the engine is
+/* Set the PROC of the backend engine. After this call the engine is
owned by the runner object. */
void
-runner_set_pid (runner_t runner, pid_t pid)
+runner_set_proc (runner_t runner, gnupg_process_t proc)
{
- if (check_already_spawned (runner, "runner_set_fds"))
+ if (check_already_spawned (runner, "runner_set_proc"))
return;
- runner->pid = pid;
+ runner->proc = proc;
}
@@ -366,15 +366,17 @@ runner_thread (void *arg)
}
/* Now wait for the process to finish. */
- if (!err && runner->pid != (pid_t)(-1))
+ if (!err && runner->proc)
{
int exitcode;
log_debug ("runner thread waiting ...\n");
- err = gnupg_wait_process (runner->name, runner->pid, 1, &exitcode);
- gnupg_release_process (runner->pid);
- runner->pid = (pid_t)(-1);
- if (err)
+ err = gnupg_process_wait (runner->proc, 1);
+ if (!err)
+ gnupg_process_ctl (runner->proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
+ gnupg_process_release (runner->proc);
+ runner->proc = NULL;
+ if (exitcode)
log_error ("running '%s' failed (exitcode=%d): %s\n",
runner->name, exitcode, gpg_strerror (err));
log_debug ("runner thread waiting finished\n");
@@ -473,7 +475,7 @@ runner_cancel (runner_t runner)
need to change the thread to wait on an event. */
runner->cancel_flag = 1;
/* For now we use the brutal way and kill the process. */
- gnupg_kill_process (runner->pid);
+ gnupg_process_terminate (runner->proc);
}
}
diff --git a/g13/runner.h b/g13/runner.h
index 36181adf9..01c395e02 100644
--- a/g13/runner.h
+++ b/g13/runner.h
@@ -49,7 +49,7 @@ runner_t runner_find_by_rid (unsigned int rid);
/* Functions to set properties of the runner. */
void runner_set_fds (runner_t runner, int in_fd, int out_fd);
-void runner_set_pid (runner_t runner, pid_t pid);
+void runner_set_proc (runner_t runner, gnupg_process_t proc);
/* Register the handler functions with a runner. */
void runner_set_handler (runner_t runner,
diff --git a/scd/app.c b/scd/app.c
index aeb773a67..74944c8ed 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -2316,6 +2316,18 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
static void
+setup_env (struct spawn_cb_arg *sca)
+{
+#ifdef HAVE_W32_SYSTEM
+ (void)sca; /* Not supported on Windows. */
+#else
+ char *v = sca->arg;
+
+ putenv (v);
+#endif
+}
+
+static void
report_change (int slot, int old_status, int cur_status)
{
char *homestr, *envstr;
@@ -2342,12 +2354,9 @@ report_change (int slot, int old_status, int cur_status)
else
{
gpg_error_t err;
- const char *args[9], *envs[2];
+ const char *args[9];
char numbuf1[30], numbuf2[30], numbuf3[30];
- envs[0] = envstr;
- envs[1] = NULL;
-
sprintf (numbuf1, "%d", slot);
sprintf (numbuf2, "0x%04X", old_status);
sprintf (numbuf3, "0x%04X", cur_status);
@@ -2364,7 +2373,12 @@ report_change (int slot, int old_status, int cur_status)
args[8] = NULL;
fname = make_filename (gnupg_homedir (), "scd-event", NULL);
- err = gnupg_spawn_process_detached (fname, args, envs);
+ err = gnupg_process_spawn (fname, args,
+ (GNUPG_PROCESS_DETACHED
+ | GNUPG_PROCESS_STDIN_NULL
+ | GNUPG_PROCESS_STDOUT_NULL
+ | GNUPG_PROCESS_STDERR_NULL),
+ setup_env, envstr, NULL);
if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
log_error ("failed to run event handler '%s': %s\n",
fname, gpg_strerror (err));
diff --git a/tests/gpgscm/ffi.c b/tests/gpgscm/ffi.c
index ce18e0794..b46d5cb61 100644
--- a/tests/gpgscm/ffi.c
+++ b/tests/gpgscm/ffi.c
@@ -42,6 +42,9 @@
#endif
#include "../../common/util.h"
+#ifdef HAVE_W32_SYSTEM
+#define NEED_STRUCT_SPAWN_CB_ARG
+#endif
#include "../../common/exechelp.h"
#include "../../common/sysutils.h"
@@ -753,25 +756,86 @@ do_es_write (scheme *sc, pointer args)
}
-
/* Process handling. */
+struct proc_object_box
+{
+ gnupg_process_t proc;
+};
+
+static void
+proc_object_finalize (scheme *sc, void *data)
+{
+ struct proc_object_box *box = data;
+ (void) sc;
+
+ if (!box->proc)
+ gnupg_process_release (box->proc);
+ xfree (box);
+}
+
+static void
+proc_object_to_string (scheme *sc, char *out, size_t size, void *data)
+{
+ struct proc_object_box *box = data;
+ (void) sc;
+
+ snprintf (out, size, "#proc %p", box->proc);
+}
+
+static struct foreign_object_vtable proc_object_vtable =
+ {
+ proc_object_finalize,
+ proc_object_to_string,
+ };
+
static pointer
-do_spawn_process (scheme *sc, pointer args)
+proc_wrap (scheme *sc, gnupg_process_t proc)
+{
+ struct proc_object_box *box = xmalloc (sizeof *box);
+ if (box == NULL)
+ return sc->NIL;
+
+ box->proc = proc;
+ return sc->vptr->mk_foreign_object (sc, &proc_object_vtable, box);
+}
+
+static struct proc_object_box *
+proc_unwrap (scheme *sc, pointer object)
+{
+ (void) sc;
+
+ if (! is_foreign_object (object))
+ return NULL;
+
+ if (sc->vptr->get_foreign_object_vtable (object) != &proc_object_vtable)
+ return NULL;
+
+ return sc->vptr->get_foreign_object_data (object);
+}
+
+#define CONVERSION_proc(SC, X) proc_unwrap (SC, X)
+#define IS_A_proc(SC, X) proc_unwrap (SC, X)
+
+
+static pointer
+do_process_spawn (scheme *sc, pointer args)
{
FFI_PROLOG ();
pointer arguments;
char **argv;
size_t len;
unsigned int flags;
-
+ gnupg_process_t proc = NULL;
estream_t infp;
estream_t outfp;
estream_t errfp;
- pid_t pid;
FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args);
FFI_ARG_OR_RETURN (sc, unsigned int, flags, number, args);
+ flags |= (GNUPG_PROCESS_STDIN_PIPE
+ | GNUPG_PROCESS_STDOUT_PIPE
+ | GNUPG_PROCESS_STDERR_PIPE);
FFI_ARGS_DONE_OR_RETURN (sc, args);
err = ffi_list2argv (sc, arguments, &argv, &len);
@@ -791,38 +855,55 @@ do_spawn_process (scheme *sc, pointer args)
fprintf (stderr, "\n");
}
- err = gnupg_spawn_process (argv[0], (const char **) &argv[1],
- NULL,
- flags,
- &infp, &outfp, &errfp, &pid);
+ err = gnupg_process_spawn (argv[0], (const char **) &argv[1],
+ flags, NULL, NULL, &proc);
+ err = gnupg_process_get_streams (proc, 0, &infp, &outfp, &errfp);
xfree (argv);
-#define IMC(A, B) \
- _cons (sc, sc->vptr->mk_integer (sc, (unsigned long) (A)), (B), 1)
+#define IMP(A, B) \
+ _cons (sc, proc_wrap (sc, (A)), (B), 1)
#define IMS(A, B) \
_cons (sc, es_wrap (sc, (A)), (B), 1)
FFI_RETURN_POINTER (sc, IMS (infp,
IMS (outfp,
IMS (errfp,
- IMC (pid, sc->NIL)))));
+ IMP (proc, sc->NIL)))));
#undef IMS
#undef IMC
}
+static void
+setup_std_fds (struct spawn_cb_arg *sca)
+{
+ int *std_fds = sca->arg;
+
+#ifdef HAVE_W32_SYSTEM
+ sca->hd[0] = std_fds[0] == -1?
+ INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle (std_fds[0]);
+ sca->hd[1] = std_fds[1] == -1?
+ INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle (std_fds[1]);
+ sca->hd[2] = std_fds[2] == -1?
+ INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle (std_fds[2]);
+#else
+ sca->fds[0] = std_fds[0];
+ sca->fds[1] = std_fds[1];
+ sca->fds[2] = std_fds[2];
+#endif
+}
+
static pointer
-do_spawn_process_fd (scheme *sc, pointer args)
+do_process_spawn_fd (scheme *sc, pointer args)
{
FFI_PROLOG ();
pointer arguments;
char **argv;
size_t len;
- int infd, outfd, errfd;
-
- pid_t pid;
+ int std_fds[3];
+ gnupg_process_t proc = NULL;
FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args);
- FFI_ARG_OR_RETURN (sc, int, infd, number, args);
- FFI_ARG_OR_RETURN (sc, int, outfd, number, args);
- FFI_ARG_OR_RETURN (sc, int, errfd, number, args);
+ FFI_ARG_OR_RETURN (sc, int, std_fds[0], number, args);
+ FFI_ARG_OR_RETURN (sc, int, std_fds[1], number, args);
+ FFI_ARG_OR_RETURN (sc, int, std_fds[2], number, args);
FFI_ARGS_DONE_OR_RETURN (sc, args);
err = ffi_list2argv (sc, arguments, &argv, &len);
@@ -839,107 +920,35 @@ do_spawn_process_fd (scheme *sc, pointer args)
fprintf (stderr, "Executing:");
for (p = argv; *p; p++)
fprintf (stderr, " '%s'", *p);
- fprintf (stderr, "\n");
+ fprintf (stderr, " (%d %d %d)\n", std_fds[0], std_fds[1], std_fds[2]);
}
- err = gnupg_spawn_process_fd (argv[0], (const char **) &argv[1],
- infd, outfd, errfd, &pid);
+ err = gnupg_process_spawn (argv[0], (const char **) &argv[1],
+ 0, setup_std_fds, std_fds, &proc);
xfree (argv);
- FFI_RETURN_INT (sc, pid);
+ FFI_RETURN_POINTER (sc, proc_wrap (sc, proc));
}
static pointer
-do_wait_process (scheme *sc, pointer args)
+do_process_wait (scheme *sc, pointer args)
{
FFI_PROLOG ();
- const char *name;
- pid_t pid;
+ struct proc_object_box *box;
int hang;
+ int retcode = -1;
- int retcode;
-
- FFI_ARG_OR_RETURN (sc, const char *, name, string, args);
- FFI_ARG_OR_RETURN (sc, pid_t, pid, number, args);
+ FFI_ARG_OR_RETURN (sc, struct proc_object_box *, box, proc, args);
FFI_ARG_OR_RETURN (sc, int, hang, bool, args);
FFI_ARGS_DONE_OR_RETURN (sc, args);
- err = gnupg_wait_process (name, pid, hang, &retcode);
- if (err == GPG_ERR_GENERAL)
- err = 0; /* Let the return code speak for itself. */
-
- FFI_RETURN_INT (sc, retcode);
-}
-
-
-static pointer
-do_wait_processes (scheme *sc, pointer args)
-{
- FFI_PROLOG ();
- pointer list_names;
- char **names;
- pointer list_pids;
- size_t i, count;
- pid_t *pids;
- int hang;
- int *retcodes;
- pointer retcodes_list = sc->NIL;
-
- FFI_ARG_OR_RETURN (sc, pointer, list_names, list, args);
- FFI_ARG_OR_RETURN (sc, pointer, list_pids, list, args);
- FFI_ARG_OR_RETURN (sc, int, hang, bool, args);
- FFI_ARGS_DONE_OR_RETURN (sc, args);
-
- if (sc->vptr->list_length (sc, list_names)
- != sc->vptr->list_length (sc, list_pids))
- return
- sc->vptr->mk_string (sc, "length of first two arguments must match");
-
- err = ffi_list2argv (sc, list_names, &names, &count);
- if (err == gpg_error (GPG_ERR_INV_VALUE))
- return ffi_sprintf (sc, "%lu%s element of first argument is "
- "neither string nor symbol",
- (unsigned long) count,
- ordinal_suffix ((int) count));
- if (err)
- FFI_RETURN_ERR (sc, err);
-
- err = ffi_list2intv (sc, list_pids, (int **) &pids, &count);
- if (err == gpg_error (GPG_ERR_INV_VALUE))
- return ffi_sprintf (sc, "%lu%s element of second argument is "
- "not a number",
- (unsigned long) count,
- ordinal_suffix ((int) count));
- if (err)
- FFI_RETURN_ERR (sc, err);
-
- retcodes = xtrycalloc (sizeof *retcodes, count);
- if (retcodes == NULL)
- {
- xfree (names);
- xfree (pids);
- FFI_RETURN_ERR (sc, gpg_error_from_syserror ());
- }
-
- err = gnupg_wait_processes ((const char **) names, pids, count, hang,
- retcodes);
- if (err == GPG_ERR_GENERAL)
- err = 0; /* Let the return codes speak. */
+ err = gnupg_process_wait (box->proc, hang);
+ if (!err)
+ err = gnupg_process_ctl (box->proc, GNUPG_PROCESS_GET_EXIT_ID, &retcode);
if (err == GPG_ERR_TIMEOUT)
- err = 0; /* We may have got some results. */
-
- for (i = 0; i < count; i++)
- retcodes_list =
- (sc->vptr->cons) (sc,
- sc->vptr->mk_integer (sc,
- (long) retcodes[count-1-i]),
- retcodes_list);
+ err = 0;
- xfree (names);
- xfree (pids);
- xfree (retcodes);
- FFI_RETURN_POINTER (sc, retcodes_list);
+ FFI_RETURN_INT (sc, retcode);
}
-
static pointer
do_pipe (scheme *sc, pointer args)
{
@@ -1398,13 +1407,12 @@ ffi_init (scheme *sc, const char *argv0, const char *scriptname,
ffi_define_function (sc, make_random_string);
/* Process management. */
- ffi_define_function (sc, spawn_process);
- ffi_define_function (sc, spawn_process_fd);
- ffi_define_function (sc, wait_process);
- ffi_define_function (sc, wait_processes);
ffi_define_function (sc, pipe);
ffi_define_function (sc, inbound_pipe);
ffi_define_function (sc, outbound_pipe);
+ ffi_define_function (sc, process_spawn);
+ ffi_define_function (sc, process_spawn_fd);
+ ffi_define_function (sc, process_wait);
/* estream functions. */
ffi_define_function_name (sc, "es-fclose", es_fclose);
diff --git a/tests/gpgscm/t-child.scm b/tests/gpgscm/t-child.scm
index fd1dcc3fe..461413b9c 100644
--- a/tests/gpgscm/t-child.scm
+++ b/tests/gpgscm/t-child.scm
@@ -69,37 +69,36 @@
(assert (string=? "" (:stderr r))))
(define (spawn what)
- (spawn-process-fd what CLOSED_FD STDOUT_FILENO STDERR_FILENO))
+ (process-spawn-fd what CLOSED_FD STDOUT_FILENO STDERR_FILENO))
-(let ((pid0 (spawn `(,(qualify "t-child") "return0")))
- (pid1 (spawn `(,(qualify "t-child") "return0"))))
- (assert (equal? '(0 0)
- (wait-processes '("child0" "child1") (list pid0 pid1) #t))))
+(let ((proc0 (spawn `(,(qualify "t-child") "return0")))
+ (proc1 (spawn `(,(qualify "t-child") "return0"))))
+ (assert (= (process-wait proc0 #t) 0))
+ (assert (= (process-wait proc1 #t) 0)))
-(let ((pid0 (spawn `(,(qualify "t-child") "return1")))
- (pid1 (spawn `(,(qualify "t-child") "return0"))))
- (assert (equal? '(1 0)
- (wait-processes '("child0" "child1") (list pid0 pid1) #t))))
+(let ((proc0 (spawn `(,(qualify "t-child") "return1")))
+ (proc1 (spawn `(,(qualify "t-child") "return0"))))
+ (assert (= (process-wait proc0 #t) 1))
+ (assert (= (process-wait proc1 #t) 0)))
-(let ((pid0 (spawn `(,(qualify "t-child") "return0")))
- (pid1 (spawn `(,(qualify "t-child") "return77")))
- (pid2 (spawn `(,(qualify "t-child") "return1"))))
- (assert (equal? '(0 77 1)
- (wait-processes '("child0" "child1" "child2")
- (list pid0 pid1 pid2) #t))))
+(let ((proc0 (spawn `(,(qualify "t-child") "return0")))
+ (proc1 (spawn `(,(qualify "t-child") "return77")))
+ (proc2 (spawn `(,(qualify "t-child") "return1"))))
+ (assert (= (process-wait proc0 #t) 0))
+ (assert (= (process-wait proc1 #t) 77))
+ (assert (= (process-wait proc2 #t) 1)))
(let* ((p (pipe))
- (pid0 (spawn-process-fd
+ (proc0 (process-spawn-fd
`(,(qualify "t-child") "hello_stdout")
CLOSED_FD (:write-end p) STDERR_FILENO))
(_ (close (:write-end p)))
- (pid1 (spawn-process-fd
+ (proc1 (process-spawn-fd
`(,(qualify "t-child") "cat")
(:read-end p) STDOUT_FILENO STDERR_FILENO)))
(close (:read-end p))
- (assert
- (equal? '(0 0)
- (wait-processes '("child0" "child1") (list pid0 pid1) #t))))
+ (assert (= (process-wait proc0 #t) 0))
+ (assert (= (process-wait proc1 #t) 0)))
(echo " world.")
(tr:do
diff --git a/tests/gpgscm/tests.scm b/tests/gpgscm/tests.scm
index db1025bbb..6a11e55f1 100644
--- a/tests/gpgscm/tests.scm
+++ b/tests/gpgscm/tests.scm
@@ -81,7 +81,7 @@
;; Process management.
(define CLOSED_FD -1)
(define (call-with-fds what infd outfd errfd)
- (wait-process (stringify what) (spawn-process-fd what infd outfd errfd) #t))
+ (process-wait (process-spawn-fd what infd outfd errfd) #t))
(define (call what)
(call-with-fds what
CLOSED_FD
@@ -92,19 +92,19 @@
(define :stdin car)
(define :stdout cadr)
(define :stderr caddr)
-(define :pid cadddr)
+(define :proc cadddr)
(define (call-with-io what in)
- (let ((h (spawn-process what 0)))
+ (let ((h (process-spawn what 0)))
(es-write (:stdin h) in)
(es-fclose (:stdin h))
(let* ((out (es-read-all (:stdout h)))
(err (es-read-all (:stderr h)))
- (result (wait-process (car what) (:pid h) #t)))
+ (result (process-wait (:proc h) #t)))
(es-fclose (:stdout h))
(es-fclose (:stderr h))
(if (> (*verbose*) 2)
- (info "Child" (:pid h) "returned:"
+ (info "Child" (:proc h) "returned:"
`((command ,(stringify what))
(status ,result)
(stdout ,out)
@@ -351,12 +351,8 @@
(define (dump)
(write (list procs source sink producer))
(newline))
- (define (add-proc command pid)
- (new (cons (list command pid) procs) source sink producer))
- (define (commands)
- (map car procs))
- (define (pids)
- (map cadr procs))
+ (define (add-proc proc)
+ (new (cons proc procs) source sink producer))
(define (set-source source')
(new procs source' sink producer))
(define (set-sink sink')
@@ -367,17 +363,19 @@
(new procs source sink producer'))))))
+(define (process-wait-list procs hang)
+ (map (lambda (p) (process-wait p hang)) procs))
+
(define (pipe:do . commands)
(let loop ((M (pipeM::new '() CLOSED_FD CLOSED_FD #f)) (cmds commands))
(if (null? cmds)
(begin
(if M::producer (M::producer))
(if (not (null? M::procs))
- (let* ((retcodes (wait-processes (map stringify (M::commands))
- (M::pids) #t))
- (results (map (lambda (p r) (append p (list r)))
+ (let* ((retcodes (process-wait-list M::procs #t))
+ (results (map (lambda (p r) (cons p r))
M::procs retcodes))
- (failed (filter (lambda (x) (not (= 0 (caddr x))))
+ (failed (filter (lambda (x) (not (= 0 (cdr x))))
results)))
(if (not (null? failed))
(throw failed))))) ; xxx nicer reporting
@@ -408,11 +406,11 @@
(define (pipe:spawn command)
(lambda (M)
(define (do-spawn M new-source)
- (let ((pid (spawn-process-fd command M::source M::sink
- (if (> (*verbose*) 0)
- STDERR_FILENO CLOSED_FD)))
+ (let ((proc (process-spawn-fd command M::source M::sink
+ (if (> (*verbose*) 0)
+ STDERR_FILENO CLOSED_FD)))
(M' (M::set-source new-source)))
- (M'::add-proc command pid)))
+ (M'::add-proc proc)))
(if (= CLOSED_FD M::sink)
(let* ((p (pipe))
(M' (do-spawn (M::set-sink (:write-end p)) (:read-end p))))
@@ -568,8 +566,8 @@
(assert (= (length enqueued) (- i 1)))
test)))))
- (define (pid->test pid)
- (let ((t (filter (lambda (x) (= pid x::pid)) procs)))
+ (define (proc->test proc)
+ (let ((t (filter (lambda (x) (eq? proc x::proc)) procs)))
(if (null? t) #f (car t))))
(define (wait)
(if (null? enqueued)
@@ -587,7 +585,7 @@
(if (null? unfinished)
(current-environment)
(let ((names (map (lambda (t) t::name) unfinished))
- (pids (map (lambda (t) t::pid) unfinished))
+ (procs (map (lambda (t) t::proc) unfinished))
(any #f))
(for-each
(lambda (test retcode)
@@ -597,8 +595,8 @@
(test::report)
(sem::release!)
(set! any #t)))
- (map pid->test pids)
- (wait-processes (map stringify names) pids hang))
+ (map proc->test procs)
+ (process-wait-list procs hang))
;; If some processes finished, try to start new ones.
(let loop ()
@@ -682,7 +680,7 @@
(define (scm setup variant name path . args)
;; Start the process.
(define (spawn-scm args' in out err)
- (spawn-process-fd `(,*argv0* ,@(verbosity (*verbose*))
+ (process-spawn-fd `(,*argv0* ,@(verbosity (*verbose*))
,(locate-test (test-name path))
,@(if setup (force setup) '())
,@args' ,@args) in out err))
@@ -691,12 +689,12 @@
(define (binary setup name path . args)
;; Start the process.
(define (spawn-binary args' in out err)
- (spawn-process-fd `(,(test-name path)
+ (process-spawn-fd `(,(test-name path)
,@(if setup (force setup) '()) ,@args' ,@args)
in out err))
(new #f name #f spawn-binary #f #f CLOSED_FD (expect-failure? name)))
- (define (new variant name directory spawn pid retcode logfd expect-failure)
+ (define (new variant name directory spawn proc retcode logfd expect-failure)
(package
;; XXX: OO glue.
@@ -721,7 +719,7 @@
;; Has the test been started yet?
(define (started?)
- (number? pid))
+ proc)
(define (open-log-file)
(unless log-file-name
@@ -738,26 +736,26 @@
(letfd ((log (open-log-file)))
(with-working-directory directory
(let* ((p (inbound-pipe))
- (pid' (spawn args 0 (:write-end p) (:write-end p))))
+ (proc' (spawn args 0 (:write-end p) (:write-end p))))
(close (:write-end p))
(splice (:read-end p) STDERR_FILENO log)
(close (:read-end p))
- (set! pid pid')
- (set! retcode (wait-process name pid' #t)))))
+ (set! proc proc')
+ (set! retcode (process-wait proc' #t)))))
(report)
(current-environment))
(define (run-sync-quiet . args)
(set-start-time!)
(with-working-directory directory
- (set! pid (spawn args CLOSED_FD CLOSED_FD CLOSED_FD)))
- (set! retcode (wait-process name pid #t))
+ (set! proc (spawn args CLOSED_FD CLOSED_FD CLOSED_FD)))
+ (set! retcode (process-wait proc #t))
(set-end-time!)
(current-environment))
(define (run-async . args)
(set-start-time!)
(let ((log (open-log-file)))
(with-working-directory directory
- (set! pid (spawn args CLOSED_FD log log)))
+ (set! proc (spawn args CLOSED_FD log log)))
(set! logfd log))
(current-environment))
(define (status)
diff --git a/tests/openpgp/defs.scm b/tests/openpgp/defs.scm
index bf3714f50..1ac25bf65 100644
--- a/tests/openpgp/defs.scm
+++ b/tests/openpgp/defs.scm
@@ -268,13 +268,14 @@
(define (gpg-pipe args0 args1 errfd)
(lambda (source sink)
(let* ((p (pipe))
- (task0 (spawn-process-fd `(,@GPG ,@args0)
+ (task0 (process-spawn-fd `(,@GPG ,@args0)
source (:write-end p) errfd))
(_ (close (:write-end p)))
- (task1 (spawn-process-fd `(,@GPG ,@args1)
+ (task1 (process-spawn-fd `(,@GPG ,@args1)
(:read-end p) sink errfd)))
(close (:read-end p))
- (wait-processes (list GPG GPG) (list task0 task1) #t))))
+ (process-wait task0 #t)
+ (process-wait task1 #t))))
(setenv "GPG_AGENT_INFO" "" #t)
(setenv "GNUPGHOME" (getcwd) #t)
diff --git a/tests/tpm2dtests/defs.scm b/tests/tpm2dtests/defs.scm
index 0fef71806..a913818f5 100644
--- a/tests/tpm2dtests/defs.scm
+++ b/tests/tpm2dtests/defs.scm
@@ -217,13 +217,14 @@
(define (gpg-pipe args0 args1 errfd)
(lambda (source sink)
(let* ((p (pipe))
- (task0 (spawn-process-fd `(,@GPG ,@args0)
+ (task0 (process-spawn-fd `(,@GPG ,@args0)
source (:write-end p) errfd))
(_ (close (:write-end p)))
- (task1 (spawn-process-fd `(,@GPG ,@args1)
+ (task1 (process-spawn-fd `(,@GPG ,@args1)
(:read-end p) sink errfd)))
(close (:read-end p))
- (wait-processes (list GPG GPG) (list task0 task1) #t))))
+ (process-wait task0 #t)
+ (process-wait task1 #t))))
;;
;; Do we have a software tpm
diff --git a/tools/gpg-card.c b/tools/gpg-card.c
index a94aabea9..3034a14c5 100644
--- a/tools/gpg-card.c
+++ b/tools/gpg-card.c
@@ -3641,7 +3641,7 @@ cmd_gpg (card_info_t info, char *argstr, int use_gpgsm)
char **argarray;
ccparray_t ccp;
const char **argv = NULL;
- pid_t pid;
+ gnupg_process_t proc;
int i;
if (!info)
@@ -3669,15 +3669,13 @@ cmd_gpg (card_info_t info, char *argstr, int use_gpgsm)
goto leave;
}
- err = gnupg_spawn_process (use_gpgsm? opt.gpgsm_program:opt.gpg_program,
- argv, NULL, (GNUPG_SPAWN_KEEP_STDOUT
- |GNUPG_SPAWN_KEEP_STDERR),
- NULL, NULL, NULL, &pid);
+ err = gnupg_process_spawn (use_gpgsm? opt.gpgsm_program:opt.gpg_program,
+ argv, GNUPG_PROCESS_STDIN_NULL, NULL, NULL,
+ &proc);
if (!err)
{
- err = gnupg_wait_process (use_gpgsm? opt.gpgsm_program:opt.gpg_program,
- pid, 1, NULL);
- gnupg_release_process (pid);
+ err = gnupg_process_wait (proc, 1);
+ gnupg_process_release (proc);
}
diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c
index 90f2f53d3..f89ab3b9c 100644
--- a/tools/gpgconf-comp.c
+++ b/tools/gpgconf-comp.c
@@ -744,7 +744,7 @@ gpg_agent_runtime_change (int killflag)
gpg_error_t err = 0;
const char *pgmname;
const char *argv[5];
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc = NULL;
int i = 0;
int cmdidx;
@@ -761,13 +761,17 @@ gpg_agent_runtime_change (int killflag)
log_assert (i < DIM(argv));
if (!err)
- err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (!err)
- err = gnupg_wait_process (pgmname, pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err));
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
}
@@ -777,7 +781,7 @@ scdaemon_runtime_change (int killflag)
gpg_error_t err = 0;
const char *pgmname;
const char *argv[9];
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc = NULL;
int i = 0;
int cmdidx;
@@ -805,13 +809,17 @@ scdaemon_runtime_change (int killflag)
log_assert (i < DIM(argv));
if (!err)
- err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (!err)
- err = gnupg_wait_process (pgmname, pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err));
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
}
@@ -822,7 +830,7 @@ tpm2daemon_runtime_change (int killflag)
gpg_error_t err = 0;
const char *pgmname;
const char *argv[9];
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc = NULL;
int i = 0;
int cmdidx;
@@ -850,13 +858,17 @@ tpm2daemon_runtime_change (int killflag)
log_assert (i < DIM(argv));
if (!err)
- err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (!err)
- err = gnupg_wait_process (pgmname, pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err));
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
}
#endif
@@ -867,7 +879,7 @@ dirmngr_runtime_change (int killflag)
gpg_error_t err = 0;
const char *pgmname;
const char *argv[6];
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc = NULL;
int i = 0;
int cmdidx;
@@ -885,13 +897,17 @@ dirmngr_runtime_change (int killflag)
log_assert (i < DIM(argv));
if (!err)
- err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (!err)
- err = gnupg_wait_process (pgmname, pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err));
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
}
@@ -901,7 +917,7 @@ keyboxd_runtime_change (int killflag)
gpg_error_t err = 0;
const char *pgmname;
const char *argv[6];
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc = NULL;
int i = 0;
int cmdidx;
@@ -919,13 +935,17 @@ keyboxd_runtime_change (int killflag)
log_assert (i < DIM(argv));
if (!err)
- err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (!err)
- err = gnupg_wait_process (pgmname, pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err));
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
}
@@ -937,7 +957,7 @@ gc_component_launch (int component)
const char *pgmname;
const char *argv[6];
int i;
- pid_t pid;
+ gnupg_process_t proc = NULL;
if (component < 0)
{
@@ -985,9 +1005,13 @@ gc_component_launch (int component)
argv[i] = NULL;
log_assert (i < DIM(argv));
- err = gnupg_spawn_process_fd (pgmname, argv, -1, -1, -1, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ |GNUPG_PROCESS_STDOUT_NULL
+ |GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (!err)
- err = gnupg_wait_process (pgmname, pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
gc_error (0, 0, "error running '%s%s%s': %s",
pgmname,
@@ -995,7 +1019,7 @@ gc_component_launch (int component)
: component == GC_COMPONENT_KEYBOXD? " --keyboxd":"",
" NOP",
gpg_strerror (err));
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
return err;
}
@@ -1336,8 +1360,7 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
const char *pgmname;
const char *argv[6];
int i;
- pid_t pid;
- int exitcode;
+ gnupg_process_t proc;
estream_t errfp;
error_line_t errlines;
@@ -1370,22 +1393,30 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
result = 0;
errlines = NULL;
- err = gnupg_spawn_process (pgmname, argv, NULL, 0,
- NULL, NULL, &errfp, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ | GNUPG_PROCESS_STDOUT_NULL
+ | GNUPG_PROCESS_STDERR_PIPE),
+ NULL, NULL, &proc);
if (err)
result |= 1; /* Program could not be run. */
else
{
+ gnupg_process_get_streams (proc, 0, NULL, NULL, &errfp);
errlines = collect_error_output (errfp,
gc_component[component].name);
- if (gnupg_wait_process (pgmname, pid, 1, &exitcode))
+ if (!gnupg_process_wait (proc, 1))
{
+ int exitcode;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
if (exitcode == -1)
result |= 1; /* Program could not be run or it
terminated abnormally. */
- result |= 2; /* Program returned an error. */
+ else if (exitcode)
+ result |= 2; /* Program returned an error. */
}
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
es_fclose (errfp);
}
@@ -1725,8 +1756,7 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed)
const char *pgmname;
const char *argv[2];
estream_t outfp;
- int exitcode;
- pid_t pid;
+ gnupg_process_t proc;
known_option_t *known_option;
gc_option_t *option;
char *line = NULL;
@@ -1759,14 +1789,19 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed)
/* First we need to read the option table from the program. */
argv[0] = "--dump-option-table";
argv[1] = NULL;
- err = gnupg_spawn_process (pgmname, argv, NULL, 0,
- NULL, &outfp, NULL, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ | GNUPG_PROCESS_STDOUT_PIPE
+ | GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (err)
{
gc_error (1, 0, "could not gather option table from '%s': %s",
pgmname, gpg_strerror (err));
}
+ gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
+
read_line_parm.pgmname = pgmname;
read_line_parm.fp = outfp;
read_line_parm.line = line;
@@ -1925,12 +1960,17 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed)
line_len = read_line_parm.line_len;
log_assert (opt_table_used + pseudo_count == opt_info_used);
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
+ {
+ int exitcode;
- err = gnupg_wait_process (pgmname, pid, 1, &exitcode);
- if (err)
- gc_error (1, 0, "running %s failed (exitcode=%d): %s",
- pgmname, exitcode, gpg_strerror (err));
- gnupg_release_process (pid);
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
+ if (exitcode)
+ gc_error (1, 0, "running %s failed (exitcode=%d): %s",
+ pgmname, exitcode, gpg_strerror (err));
+ }
+ gnupg_process_release (proc);
/* Make the gpgrt option table and the internal option table available. */
gc_component[component].opt_table = opt_table;
@@ -1940,14 +1980,19 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed)
/* Now read the default options. */
argv[0] = "--gpgconf-list";
argv[1] = NULL;
- err = gnupg_spawn_process (pgmname, argv, NULL, 0,
- NULL, &outfp, NULL, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ | GNUPG_PROCESS_STDOUT_PIPE
+ | GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (err)
{
gc_error (1, 0, "could not gather active options from '%s': %s",
pgmname, gpg_strerror (err));
}
+ gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
+
while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
{
char *linep;
@@ -2030,11 +2075,17 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed)
if (es_fclose (outfp))
gc_error (1, errno, "error closing %s", pgmname);
- err = gnupg_wait_process (pgmname, pid, 1, &exitcode);
- if (err)
- gc_error (1, 0, "running %s failed (exitcode=%d): %s",
- pgmname, exitcode, gpg_strerror (err));
- gnupg_release_process (pid);
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
+ {
+ int exitcode;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
+ if (exitcode)
+ gc_error (1, 0, "running %s failed (exitcode=%d): %s",
+ pgmname, exitcode, gpg_strerror (err));
+ }
+ gnupg_process_release (proc);
/* At this point, we can parse the configuration file. */
diff --git a/tools/gpgconf.c b/tools/gpgconf.c
index 4afc4e9fd..bb9ac5419 100644
--- a/tools/gpgconf.c
+++ b/tools/gpgconf.c
@@ -1173,17 +1173,19 @@ show_versions_via_dirmngr (estream_t fp)
const char *pgmname;
const char *argv[2];
estream_t outfp;
- pid_t pid;
+ gnupg_process_t proc;
char *line = NULL;
size_t line_len = 0;
ssize_t length;
- int exitcode;
pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
argv[0] = "--gpgconf-versions";
argv[1] = NULL;
- err = gnupg_spawn_process (pgmname, argv, NULL, 0,
- NULL, &outfp, NULL, &pid);
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDIN_NULL
+ | GNUPG_PROCESS_STDOUT_PIPE
+ | GNUPG_PROCESS_STDERR_NULL),
+ NULL, NULL, &proc);
if (err)
{
log_error ("error spawning %s: %s", pgmname, gpg_strerror (err));
@@ -1191,6 +1193,7 @@ show_versions_via_dirmngr (estream_t fp)
return;
}
+ gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
{
/* Strip newline and carriage return, if present. */
@@ -1211,14 +1214,17 @@ show_versions_via_dirmngr (estream_t fp)
pgmname, gpg_strerror (err));
}
- err = gnupg_wait_process (pgmname, pid, 1, &exitcode);
- if (err)
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
{
+ int exitcode;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
log_error ("running %s failed (exitcode=%d): %s\n",
pgmname, exitcode, gpg_strerror (err));
es_fprintf (fp, "[error: can't get further info]\n");
}
- gnupg_release_process (pid);
+ gnupg_process_release (proc);
xfree (line);
}
diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c
index f52295b5c..ebcfc5229 100644
--- a/tools/gpgtar-create.c
+++ b/tools/gpgtar-create.c
@@ -994,7 +994,7 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
estream_t files_from_stream = NULL;
estream_t outstream = NULL;
int eof_seen = 0;
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc = NULL;
memset (scanctrl, 0, sizeof *scanctrl);
scanctrl->flist_tail = &scanctrl->flist;
@@ -1197,14 +1197,13 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
goto leave;
}
- err = gnupg_spawn_process (opt.gpg_program, argv,
- except[0] == -1? NULL : except,
- (GNUPG_SPAWN_KEEP_STDOUT
- | GNUPG_SPAWN_KEEP_STDERR),
- &outstream, NULL, NULL, &pid);
+ err = gnupg_process_spawn (opt.gpg_program, argv,
+ GNUPG_PROCESS_STDIN_PIPE,
+ gnupg_spawn_helper, except, &proc);
xfree (argv);
if (err)
goto leave;
+ gnupg_process_get_streams (proc, 0, &outstream, NULL, NULL);
es_set_binary (outstream);
}
else if (opt.outfile) /* No crypto */
@@ -1240,30 +1239,32 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
goto leave;
- if (pid != (pid_t)(-1))
+ if (proc)
{
- int exitcode;
-
err = es_fclose (outstream);
outstream = NULL;
if (err)
log_error ("error closing pipe: %s\n", gpg_strerror (err));
- else
+
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
{
- err = gnupg_wait_process (opt.gpg_program, pid, 1, &exitcode);
- if (err)
+ int exitcode;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
+ if (exitcode)
log_error ("running %s failed (exitcode=%d): %s",
opt.gpg_program, exitcode, gpg_strerror (err));
- gnupg_release_process (pid);
- pid = (pid_t)(-1);
}
+ gnupg_process_release (proc);
+ proc = NULL;
}
leave:
if (!err)
{
gpg_error_t first_err;
- if (outstream != es_stdout || pid != (pid_t)(-1))
+ if (outstream != es_stdout)
first_err = es_fclose (outstream);
else
first_err = es_fflush (outstream);
diff --git a/tools/gpgtar-extract.c b/tools/gpgtar-extract.c
index bc2e672de..9d5abd33d 100644
--- a/tools/gpgtar-extract.c
+++ b/tools/gpgtar-extract.c
@@ -324,7 +324,7 @@ gpgtar_extract (const char *filename, int decrypt)
char *dirname = NULL;
struct tarinfo_s tarinfo_buffer;
tarinfo_t tarinfo = &tarinfo_buffer;
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc;
char *logfilename = NULL;
@@ -410,14 +410,14 @@ gpgtar_extract (const char *filename, int decrypt)
goto leave;
}
- err = gnupg_spawn_process (opt.gpg_program, argv,
- except[0] == -1? NULL : except,
- ((filename? 0 : GNUPG_SPAWN_KEEP_STDIN)
- | GNUPG_SPAWN_KEEP_STDERR),
- NULL, &stream, NULL, &pid);
+ err = gnupg_process_spawn (opt.gpg_program, argv,
+ ((filename ? GNUPG_PROCESS_STDIN_NULL : 0)
+ | GNUPG_PROCESS_STDOUT_PIPE),
+ gnupg_spawn_helper, except, &proc);
xfree (argv);
if (err)
goto leave;
+ gnupg_process_get_streams (proc, 0, NULL, &stream, NULL);
es_set_binary (stream);
}
else if (filename)
@@ -457,26 +457,27 @@ gpgtar_extract (const char *filename, int decrypt)
header = NULL;
}
- if (pid != (pid_t)(-1))
+ if (proc)
{
- int exitcode;
-
err = es_fclose (stream);
stream = NULL;
if (err)
log_error ("error closing pipe: %s\n", gpg_strerror (err));
- else
+
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
{
- err = gnupg_wait_process (opt.gpg_program, pid, 1, &exitcode);
- if (err)
+ int exitcode;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
+ if (exitcode)
log_error ("running %s failed (exitcode=%d): %s",
opt.gpg_program, exitcode, gpg_strerror (err));
- gnupg_release_process (pid);
- pid = (pid_t)(-1);
}
+ gnupg_process_release (proc);
+ proc = NULL;
}
-
leave:
free_strlist (extheader);
xfree (header);
diff --git a/tools/gpgtar-list.c b/tools/gpgtar-list.c
index c5bf25825..6d824d35c 100644
--- a/tools/gpgtar-list.c
+++ b/tools/gpgtar-list.c
@@ -460,7 +460,7 @@ gpgtar_list (const char *filename, int decrypt)
strlist_t extheader = NULL;
struct tarinfo_s tarinfo_buffer;
tarinfo_t tarinfo = &tarinfo_buffer;
- pid_t pid = (pid_t)(-1);
+ gnupg_process_t proc = NULL;
memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
@@ -503,14 +503,14 @@ gpgtar_list (const char *filename, int decrypt)
goto leave;
}
- err = gnupg_spawn_process (opt.gpg_program, argv,
- except[0] == -1? NULL : except,
- ((filename? 0 : GNUPG_SPAWN_KEEP_STDIN)
- | GNUPG_SPAWN_KEEP_STDERR),
- NULL, &stream, NULL, &pid);
+ err = gnupg_process_spawn (opt.gpg_program, argv,
+ ((filename ? GNUPG_PROCESS_STDIN_NULL : 0)
+ | GNUPG_PROCESS_STDOUT_PIPE),
+ gnupg_spawn_helper, except, &proc);
xfree (argv);
if (err)
goto leave;
+ gnupg_process_get_streams (proc, 0, NULL, &stream, NULL);
es_set_binary (stream);
}
else if (filename) /* No decryption requested. */
@@ -550,23 +550,24 @@ gpgtar_list (const char *filename, int decrypt)
header = NULL;
}
- if (pid != (pid_t)(-1))
+ if (proc)
{
- int exitcode;
-
err = es_fclose (stream);
stream = NULL;
if (err)
log_error ("error closing pipe: %s\n", gpg_strerror (err));
- else
+
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
{
- err = gnupg_wait_process (opt.gpg_program, pid, 1, &exitcode);
- if (err)
- log_error ("running %s failed (exitcode=%d): %s",
- opt.gpg_program, exitcode, gpg_strerror (err));
- gnupg_release_process (pid);
- pid = (pid_t)(-1);
+ int exitcode;
+
+ gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
+ log_error ("running %s failed (exitcode=%d): %s",
+ opt.gpg_program, exitcode, gpg_strerror (err));
}
+ gnupg_process_release (proc);
+ proc = NULL;
}
leave: