aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS25
-rw-r--r--README2
-rw-r--r--agent/call-daemon.c4
-rw-r--r--agent/call-pinentry.c5
-rw-r--r--agent/genkey.c18
-rw-r--r--agent/gpg-agent.c2
-rw-r--r--common/Makefile.am4
-rw-r--r--common/asshelp.c14
-rw-r--r--common/exechelp-posix.c993
-rw-r--r--common/exechelp-w32.c1207
-rw-r--r--common/exechelp.h231
-rw-r--r--common/exectool.c40
-rw-r--r--common/iobuf.c159
-rw-r--r--common/iobuf.h3
-rw-r--r--common/miscellaneous.c106
-rw-r--r--common/sysutils.c121
-rw-r--r--common/sysutils.h1
-rw-r--r--common/t-exechelp.c152
-rw-r--r--common/t-iobuf.c56
-rw-r--r--common/util.h2
-rw-r--r--configure.ac6
-rw-r--r--dirmngr/dirmngr.c7
-rw-r--r--dirmngr/ldap-wrapper.c79
-rw-r--r--g10/call-keyboxd.c13
-rw-r--r--g10/cipher-aead.c7
-rw-r--r--g10/cipher-cfb.c9
-rw-r--r--g10/encrypt.c103
-rw-r--r--g10/mainproc.c12
-rw-r--r--g10/photoid.c67
-rw-r--r--g10/plaintext.c3
-rw-r--r--g10/sign.c13
-rw-r--r--g13/be-encfs.c63
-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--kbx/kbx-client-util.c33
-rw-r--r--po/ja.po8
-rw-r--r--scd/app.c21
-rw-r--r--scd/command.c19
-rw-r--r--sm/keydb.c13
-rw-r--r--tests/gpgscm/ffi.c514
-rw-r--r--tests/gpgscm/scheme.c4
-rw-r--r--tests/gpgscm/t-child.scm39
-rw-r--r--tests/gpgscm/tests.scm93
-rw-r--r--tests/openpgp/defs.scm7
-rw-r--r--tests/tpm2dtests/defs.scm7
-rw-r--r--tools/gpg-card.c16
-rw-r--r--tools/gpg-connect-agent.c83
-rw-r--r--tools/gpgconf-comp.c115
-rw-r--r--tools/gpgconf.c18
-rw-r--r--tools/gpgtar-create.c49
-rw-r--r--tools/gpgtar-extract.c46
-rw-r--r--tools/gpgtar-list.c49
-rw-r--r--tools/gpgtar.c25
-rw-r--r--tools/gpgtar.h2
56 files changed, 2840 insertions, 1890 deletions
diff --git a/NEWS b/NEWS
index 94cd00c9f..d2560a665 100644
--- a/NEWS
+++ b/NEWS
@@ -1,11 +1,8 @@
-Noteworthy changes in version 2.4.4 (unreleased)
+Noteworthy changes in version 2.5.0 (unreleased)
------------------------------------------------
- Release-info: https://dev.gnupg.org/T6578
-
-Noteworthy changes in version 2.4.3 (2023-07-04)
-------------------------------------------------
+ Changes also found in 2.4.3:
* gpg: Set default expiration date to 3 years. [T2701]
@@ -47,12 +44,7 @@ Noteworthy changes in version 2.4.3 (2023-07-04)
* scd: Fix authentication with Administration Key for PIV.
[rG25b59cf6ce]
- See-also: gnupg-announce/2023q3/000480.html
- Release-info: https://dev.gnupg.org/T6509
-
-
-Noteworthy changes in version 2.4.2 (2023-05-30)
-------------------------------------------------
+ Changes also found in 2.4.2:
* gpg: Print a warning if no more encryption subkeys are left over
after changing the expiration date. [rGef2c3d50fa]
@@ -74,8 +66,14 @@ Noteworthy changes in version 2.4.2 (2023-05-30)
* w32: Avoid using the VirtualStore. [T6403]
- See-also: gnupg-announce/2023q2/000479.html
- Release-info: https://dev.gnupg.org/T6506
+
+Release dates of 2.4 versions
+-----------------------------
+
+Version 2.4.3 (2023-07-04) https://dev.gnupg.org/T6509
+Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506
+Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454
+Version 2.4.0 (2022-12-16) https://dev.gnupg.org/T6302
Noteworthy changes in version 2.4.1 (2023-04-28)
@@ -1671,6 +1669,7 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
Release dates of 2.2 versions
-----------------------------
+Version 2.2.41 (2022-12-09) https://dev.gnupg.org/T6280
Version 2.2.40 (2022-10-10) https://dev.gnupg.org/T6181
Version 2.2.39 (2022-09-02) https://dev.gnupg.org/T6175
Version 2.2.38 (2022-09-01) https://dev.gnupg.org/T6159
diff --git a/README b/README
index c7887fc0f..aa8b3e12b 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
The GNU Privacy Guard
=======================
- Version 2.4
+ Version 2.5 (devel)
Copyright 1997-2019 Werner Koch
Copyright 1998-2021 Free Software Foundation, Inc.
diff --git a/agent/call-daemon.c b/agent/call-daemon.c
index e1c5669e9..2699595e2 100644
--- a/agent/call-daemon.c
+++ b/agent/call-daemon.c
@@ -471,8 +471,8 @@ daemon_start (enum daemon_type type, ctrl_t ctrl)
char buf[100];
#ifdef HAVE_W32_SYSTEM
- snprintf (buf, sizeof buf, "OPTION event-signal=%lx",
- (unsigned long)get_agent_daemon_notify_event ());
+ snprintf (buf, sizeof buf, "OPTION event-signal=%p",
+ get_agent_daemon_notify_event ());
#else
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
#endif
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index 656d5f623..2369dffc2 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -128,8 +128,9 @@ initialize_module_call_pinentry (void)
void
agent_query_dump_state (void)
{
- log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
- entry_ctx, (long)assuan_get_pid (entry_ctx), (void*)popup_tid);
+ log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%lx\n",
+ entry_ctx, (long)assuan_get_pid (entry_ctx),
+ (unsigned long)popup_tid);
}
/* Called to make sure that a popup window owned by the current
diff --git a/agent/genkey.c b/agent/genkey.c
index 741c05f4f..cf37cdafc 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -100,7 +100,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;
@@ -143,11 +143,17 @@ 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,
+ 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)
{
@@ -158,11 +164,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/agent/gpg-agent.c b/agent/gpg-agent.c
index 1db422737..e55cd0b7c 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -3115,7 +3115,7 @@ handle_connections (gnupg_fd_t listen_fd,
/* Shutdown test. */
if (shutdown_pending)
{
- if (active_connections == 0)
+ if (active_connections == 0 || is_supervised)
break; /* ready */
/* Do not accept new connections but keep on running the
diff --git a/common/Makefile.am b/common/Makefile.am
index d5ab038bf..0d5af3e5c 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -161,11 +161,11 @@ module_tests = t-stringhelp t-timestuff \
t-convert t-percent t-gettime t-sysutils t-sexputil \
t-session-env t-openpgp-oid t-ssh-utils \
t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
- t-name-value t-ccparray t-recsel t-w32-cmdline
+ t-name-value t-ccparray t-recsel t-w32-cmdline t-exechelp
if HAVE_W32_SYSTEM
module_tests += t-w32-reg
else
-module_tests += t-exechelp t-exectool
+module_tests += t-exectool
endif
if MAINTAINER_MODE
diff --git a/common/asshelp.c b/common/asshelp.c
index eb3e41bf5..8b3df2a4b 100644
--- a/common/asshelp.c
+++ b/common/asshelp.c
@@ -523,16 +523,12 @@ start_new_service (assuan_context_t *r_ctx,
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
{
#ifdef HAVE_W32_SYSTEM
- err = gnupg_spawn_process_detached (program? program : program_name,
- argv, NULL);
+ err = gnupg_process_spawn (program? program : program_name, argv,
+ GNUPG_PROCESS_DETACHED,
+ NULL, NULL, 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,
+ 0, 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..7b20a3796 100644
--- a/common/exechelp-posix.c
+++ b/common/exechelp-posix.c
@@ -273,73 +273,6 @@ get_all_open_fds (void)
}
-/* The exec core used right after the fork. This will never return. */
-static void
-do_exec (const char *pgmname, const char *argv[],
- int fd_in, int fd_out, int fd_err,
- int *except, unsigned int flags)
-{
- char **arg_list;
- int i, j;
- int fds[3];
- int nodevnull[3];
-
- fds[0] = fd_in;
- fds[1] = fd_out;
- fds[2] = fd_err;
-
- nodevnull[0] = !!(flags & GNUPG_SPAWN_KEEP_STDIN);
- nodevnull[1] = !!(flags & GNUPG_SPAWN_KEEP_STDOUT);
- nodevnull[2] = !!(flags & GNUPG_SPAWN_KEEP_STDERR);
-
- /* Create the command line argument array. */
- i = 0;
- if (argv)
- while (argv[i])
- i++;
- arg_list = xcalloc (i+2, sizeof *arg_list);
- arg_list[0] = strrchr (pgmname, '/');
- if (arg_list[0])
- arg_list[0]++;
- else
- arg_list[0] = xstrdup (pgmname);
- if (argv)
- for (i=0,j=1; argv[i]; i++, j++)
- arg_list[j] = (char*)argv[i];
-
- /* Assign /dev/null to unused FDs. */
- for (i=0; i <= 2; i++)
- {
- if (nodevnull[i])
- continue;
- if (fds[i] == -1)
- {
- fds[i] = open ("/dev/null", i? O_WRONLY : O_RDONLY);
- if (fds[i] == -1)
- log_fatal ("failed to open '%s': %s\n",
- "/dev/null", strerror (errno));
- }
- }
-
- /* Connect the standard files. */
- for (i=0; i <= 2; i++)
- {
- if (nodevnull[i])
- continue;
- if (fds[i] != i && dup2 (fds[i], i) == -1)
- log_fatal ("dup2 std%s failed: %s\n",
- i==0?"in":i==1?"out":"err", strerror (errno));
- }
-
- /* Close all other files. */
- close_all_fds (3, except);
-
- execv (pgmname, arg_list);
- /* No way to print anything, as we have closed all streams. */
- _exit (127);
-}
-
-
static gpg_error_t
do_create_pipe (int filedes[2])
{
@@ -431,487 +364,669 @@ gnupg_close_pipe (int fd)
close (fd);
}
+#include <sys/socket.h>
-/* Fork and exec the PGMNAME, see exechelp.h for details. */
-gpg_error_t
-gnupg_spawn_process (const char *pgmname, const char *argv[],
- int *except, unsigned int flags,
- estream_t *r_infp,
- estream_t *r_outfp,
- estream_t *r_errfp,
- pid_t *pid)
-{
- gpg_error_t err;
- int inpipe[2] = {-1, -1};
- int outpipe[2] = {-1, -1};
- int errpipe[2] = {-1, -1};
- estream_t infp = NULL;
- estream_t outfp = NULL;
- estream_t errfp = NULL;
- int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
+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;
+};
- if (r_infp)
- *r_infp = NULL;
- if (r_outfp)
- *r_outfp = NULL;
- if (r_errfp)
- *r_errfp = NULL;
- *pid = (pid_t)(-1); /* Always required. */
+static int gnupg_process_syscall_func_initialized;
- if (r_infp)
- {
- err = create_pipe_and_estream (inpipe, &infp, 1, nonblock);
- if (err)
- return err;
- }
+/* Functions called before and after blocking syscalls. */
+static void (*pre_syscall_func) (void);
+static void (*post_syscall_func) (void);
- if (r_outfp)
+static void
+check_syscall_func (void)
+{
+ if (!gnupg_process_syscall_func_initialized)
{
- err = create_pipe_and_estream (outpipe, &outfp, 0, nonblock);
- if (err)
- {
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != -1)
- close (inpipe[1]);
- if (inpipe[0] != -1)
- close (inpipe[0]);
-
- return err;
- }
+ gpgrt_get_syscall_clamp (&pre_syscall_func, &post_syscall_func);
+ gnupg_process_syscall_func_initialized = 1;
}
+}
- if (r_errfp)
- {
- err = create_pipe_and_estream (errpipe, &errfp, 0, nonblock);
- if (err)
- {
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != -1)
- close (inpipe[1]);
- if (inpipe[0] != -1)
- close (inpipe[0]);
-
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != -1)
- close (outpipe[0]);
- if (outpipe[1] != -1)
- close (outpipe[1]);
-
- return err;
- }
- }
+static void
+pre_syscall (void)
+{
+ if (pre_syscall_func)
+ pre_syscall_func ();
+}
+
+static void
+post_syscall (void)
+{
+ if (post_syscall_func)
+ post_syscall_func ();
+}
- *pid = fork ();
- if (*pid == (pid_t)(-1))
- {
- err = my_error_from_syserror ();
- log_error (_("error forking process: %s\n"), gpg_strerror (err));
-
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != -1)
- close (inpipe[1]);
- if (inpipe[0] != -1)
- close (inpipe[0]);
-
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != -1)
- close (outpipe[0]);
- if (outpipe[1] != -1)
- close (outpipe[1]);
-
- if (errfp)
- es_fclose (errfp);
- else if (errpipe[0] != -1)
- close (errpipe[0]);
- if (errpipe[1] != -1)
- close (errpipe[1]);
- return err;
- }
+static gpg_err_code_t
+do_create_socketpair (int filedes[2])
+{
+ gpg_error_t err = 0;
- if (!*pid)
+ pre_syscall ();
+ if (socketpair (AF_LOCAL, SOCK_STREAM, 0, filedes) == -1)
{
- /* This is the child. */
- gcry_control (GCRYCTL_TERM_SECMEM);
- es_fclose (infp);
- es_fclose (outfp);
- es_fclose (errfp);
- do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1],
- except, flags);
- /*NOTREACHED*/
+ err = gpg_err_code_from_syserror ();
+ filedes[0] = filedes[1] = -1;
}
+ post_syscall ();
- /* This is the parent. */
- if (inpipe[0] != -1)
- close (inpipe[0]);
- if (outpipe[1] != -1)
- close (outpipe[1]);
- if (errpipe[1] != -1)
- close (errpipe[1]);
+ return err;
+}
- if (r_infp)
- *r_infp = infp;
- if (r_outfp)
- *r_outfp = outfp;
- if (r_errfp)
- *r_errfp = errfp;
+static int
+posix_open_null (int for_write)
+{
+ int fd;
- return 0;
+ 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;
-/* Simplified version of gnupg_spawn_process. This function forks and
- then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
- and ERRFD to stderr (any of them may be -1 to connect them to
- /dev/null). The arguments for the process are expected in the NULL
- terminated array ARGV. The program name itself should not be
- included there. Calling gnupg_wait_process is required.
+ /* Assign /dev/null to unused FDs. */
+ for (i = 0; i <= 2; i++)
+ if (sca->fds[i] == -1)
+ sca->fds[i] = posix_open_null (i);
- Returns 0 on success or an error code. */
-gpg_error_t
-gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
- int infd, int outfd, int errfd, pid_t *pid)
+ /* 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 (const char *pgmname, const char *argv[],
+ void (*spawn_cb) (struct spawn_cb_arg *), void *spawn_cb_arg)
{
- gpg_error_t err;
+ gpg_err_code_t ec;
+ pid_t pid;
- *pid = fork ();
- if (*pid == (pid_t)(-1))
+ /* FIXME: Is this GnuPG specific or should we keep it. */
+ if (getuid() != geteuid())
{
- err = my_error_from_syserror ();
- log_error (_("error forking process: %s\n"), strerror (errno));
- return err;
+ xfree (argv);
+ return GPG_ERR_BUG;
}
- if (!*pid)
+ if (access (pgmname, X_OK))
{
- gcry_control (GCRYCTL_TERM_SECMEM);
- /* Run child. */
- do_exec (pgmname, argv, infd, outfd, errfd, NULL, 0);
- /*NOTREACHED*/
+ ec = gpg_err_code_from_syserror ();
+ xfree (argv);
+ return ec;
}
- return 0;
-}
-
-
-
+ 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 (argv);
+ return ec;
+ }
-/* Waiting for child processes.
+ if (!pid)
+ {
+ pid_t pid2;
+ struct spawn_cb_arg sca;
- waitpid(2) may return information about terminated children that we
- did not yet request, and there is no portable way to wait for a
- specific set of children.
+ if (setsid() == -1 || chdir ("/"))
+ _exit (1);
- As a workaround, we store the results of children for later use.
+ 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. */
- XXX: This assumes that PIDs are not reused too quickly. */
+ call_spawn_cb (&sca, -1, -1, -1, spawn_cb, spawn_cb_arg);
-struct terminated_child
-{
- pid_t pid;
- int exitcode;
- struct terminated_child *next;
-};
+ my_exec (pgmname, argv, &sca);
+ /*NOTREACHED*/
+ }
-struct terminated_child *terminated_children;
+ 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 ();
+ return 0;
+}
-static gpg_error_t
-store_result (pid_t pid, int exitcode)
+void
+gnupg_spawn_helper (struct spawn_cb_arg *sca)
{
- struct terminated_child *c;
+ int *user_except = sca->arg;
+ sca->except_fds = user_except;
+}
- c = xtrymalloc (sizeof *c);
- if (c == NULL)
- return gpg_err_code_from_syserror ();
+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;
- c->pid = pid;
- c->exitcode = exitcode;
- c->next = terminated_children;
- terminated_children = c;
+ check_syscall_func ();
- return 0;
-}
+ 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;
-static int
-get_result (pid_t pid, int *r_exitcode)
-{
- struct terminated_child *c, **prevp;
+ if (argv1)
+ for (i=0, j=1; argv1[i]; i++, j++)
+ argv[j] = argv1[i];
- for (prevp = &terminated_children, c = terminated_children;
- c;
- prevp = &c->next, c = c->next)
- if (c->pid == pid)
- {
- *prevp = c->next;
- *r_exitcode = c->exitcode;
- xfree (c);
- return 1;
- }
+ if ((flags & GNUPG_PROCESS_DETACHED))
+ {
+ if ((flags & GNUPG_PROCESS_STDFDS_SETTING))
+ {
+ xfree (argv);
+ return GPG_ERR_INV_FLAG;
+ }
- return 0;
-}
+ /* In detached case, it must be no R_PROCESS. */
+ if (r_process)
+ {
+ xfree (argv);
+ return GPG_ERR_INV_ARG;
+ }
+ return spawn_detached (pgmname, argv, spawn_cb, spawn_cb_arg);
+ }
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
-{
- gpg_err_code_t ec;
- int i, status;
+ process = xtrycalloc (1, sizeof (struct gnupg_process));
+ if (process == NULL)
+ {
+ xfree (argv);
+ return gpg_err_code_from_syserror ();
+ }
- if (r_exitcode)
- *r_exitcode = -1;
+ process->pgmname = pgmname;
+ process->flags = flags;
- if (pid == (pid_t)(-1))
- return gpg_error (GPG_ERR_INV_VALUE);
+ 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_KEEP))
+ {
+ fd_in[0] = 0;
+ fd_in[1] = -1;
+ }
+ else
+ {
+ fd_in[0] = -1;
+ fd_in[1] = -1;
+ }
-#ifdef USE_NPTH
- i = npth_waitpid (pid, &status, hang? 0:WNOHANG);
-#else
- while ((i=waitpid (pid, &status, hang? 0:WNOHANG)) == (pid_t)(-1)
- && errno == EINTR);
-#endif
+ 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_KEEP))
+ {
+ fd_out[0] = -1;
+ fd_out[1] = 1;
+ }
+ else
+ {
+ fd_out[0] = -1;
+ fd_out[1] = -1;
+ }
+ }
- if (i == (pid_t)(-1))
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
{
- ec = gpg_err_code_from_errno (errno);
- log_error (_("waiting for process %d to terminate failed: %s\n"),
- (int)pid, strerror (errno));
+ 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 (!i)
+ else if ((flags & GNUPG_PROCESS_STDERR_KEEP))
{
- ec = GPG_ERR_TIMEOUT; /* Still running. */
+ fd_err[0] = -1;
+ fd_err[1] = 2;
}
- else if (WIFEXITED (status) && WEXITSTATUS (status) == 127)
+ else
{
- log_error (_("error running '%s': probably not installed\n"), pgmname);
- ec = GPG_ERR_CONFIGURATION;
+ fd_err[0] = -1;
+ fd_err[1] = -1;
}
- else if (WIFEXITED (status) && WEXITSTATUS (status))
+
+ pre_syscall ();
+ pid = fork ();
+ post_syscall ();
+ if (pid == (pid_t)(-1))
{
- if (!r_exitcode)
- log_error (_("error running '%s': exit status %d\n"), pgmname,
- WEXITSTATUS (status));
- else
- *r_exitcode = WEXITSTATUS (status);
- ec = GPG_ERR_GENERAL;
+ 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;
}
- else if (!WIFEXITED (status))
+
+ if (!pid)
{
- log_error (_("error running '%s': terminated\n"), pgmname);
- ec = GPG_ERR_GENERAL;
+ 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*/
}
- else
+
+ 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)
{
- if (r_exitcode)
- *r_exitcode = 0;
- ec = 0;
+ ec = gnupg_process_wait (process, 1);
+ gnupg_process_release (process);
+ return ec;
}
- return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+ *r_process = process;
+ return 0;
}
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
- int hang, int *r_exitcodes)
+static gpg_err_code_t
+process_kill (gnupg_process_t process, int sig)
{
gpg_err_code_t ec = 0;
- size_t i, left;
- int *dummy = NULL;
+ pid_t pid = process->pid;
- if (r_exitcodes == NULL)
+ 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)
{
- dummy = r_exitcodes = xtrymalloc (sizeof *r_exitcodes * count);
- if (dummy == NULL)
- return gpg_err_code_from_syserror ();
+ *r_fd_in = process->fd_in;
+ process->fd_in = -1;
}
-
- for (i = 0, left = count; i < count; i++)
+ if (r_fd_out)
{
- int status = -1;
+ *r_fd_out = process->fd_out;
+ process->fd_out = -1;
+ }
+ if (r_fd_err)
+ {
+ *r_fd_err = process->fd_err;
+ process->fd_err = -1;
+ }
- /* Skip invalid PID. */
- if (pids[i] == (pid_t)(-1))
- {
- r_exitcodes[i] = -1;
- left -= 1;
- continue;
- }
+ return 0;
+}
- /* See if there was a previously stored result for this pid. */
- if (get_result (pids[i], &status))
- left -= 1;
+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;
- r_exitcodes[i] = status;
+ 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;
+}
- while (left > 0)
+static gpg_err_code_t
+process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr)
+{
+ switch (request)
{
- pid_t pid;
- int status;
+ case GNUPG_PROCESS_NOP:
+ return 0;
-#ifdef USE_NPTH
- pid = npth_waitpid (-1, &status, hang ? 0 : WNOHANG);
-#else
- while ((pid = waitpid (-1, &status, hang ? 0 : WNOHANG)) == (pid_t)(-1)
- && errno == EINTR);
-#endif
+ case GNUPG_PROCESS_GET_PROC_ID:
+ {
+ int *r_id = va_arg (arg_ptr, int *);
- if (pid == (pid_t)(-1))
- {
- ec = gpg_err_code_from_errno (errno);
- log_error (_("waiting for processes to terminate failed: %s\n"),
- strerror (errno));
- break;
- }
- else if (!pid)
- {
- ec = GPG_ERR_TIMEOUT; /* Still running. */
- break;
- }
- else
- {
- for (i = 0; i < count; i++)
- if (pid == pids[i])
- break;
+ if (r_id == NULL)
+ return GPG_ERR_INV_VALUE;
- if (i == count)
- {
- /* No match, store this result. */
- ec = store_result (pid, status);
- if (ec)
- break;
- continue;
- }
+ *r_id = (int)process->pid;
+ return 0;
+ }
- /* Process PIDS[i] died. */
- if (r_exitcodes[i] != (pid_t) -1)
- {
- log_error ("PID %d was reused", pid);
- ec = GPG_ERR_GENERAL;
- break;
- }
+ case GNUPG_PROCESS_GET_EXIT_ID:
+ {
+ int status = process->wstatus;
+ int *r_exit_status = va_arg (arg_ptr, int *);
- left -= 1;
- r_exitcodes[i] = status;
- }
- }
+ if (!process->terminated)
+ return GPG_ERR_UNFINISHED;
- for (i = 0; i < count; i++)
- {
- if (r_exitcodes[i] == -1)
- continue;
+ if (WIFEXITED (status))
+ {
+ if (r_exit_status)
+ *r_exit_status = WEXITSTATUS (status);
+ }
+ else
+ *r_exit_status = -1;
- if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]) == 127)
- {
- log_error (_("error running '%s': probably not installed\n"),
- pgmnames[i]);
- ec = GPG_ERR_CONFIGURATION;
- }
- else if (WIFEXITED (r_exitcodes[i]) && WEXITSTATUS (r_exitcodes[i]))
- {
- if (dummy)
- log_error (_("error running '%s': exit status %d\n"),
- pgmnames[i], WEXITSTATUS (r_exitcodes[i]));
- else
- r_exitcodes[i] = WEXITSTATUS (r_exitcodes[i]);
- ec = GPG_ERR_GENERAL;
- }
- else if (!WIFEXITED (r_exitcodes[i]))
- {
- log_error (_("error running '%s': terminated\n"), pgmnames[i]);
- ec = GPG_ERR_GENERAL;
- }
+ 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;
}
- xfree (dummy);
- return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+ return GPG_ERR_UNKNOWN_COMMAND;
}
-
-
-void
-gnupg_release_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...)
{
- (void)pid;
-}
+ 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;
+}
-/* Spawn a new process and immediately detach from it. The name of
- the program to exec is PGMNAME and its arguments are in ARGV (the
- programname is automatically passed as first argument).
- Environment strings in ENVP are set. An error is returned if
- pgmname is not executable; to make this work it is necessary to
- provide an absolute file name. All standard file descriptors are
- connected to /dev/null. */
-gpg_error_t
-gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
- const char *envp[] )
+gpg_err_code_t
+gnupg_process_wait (gnupg_process_t process, int hang)
{
gpg_err_code_t ec;
+ int status;
pid_t pid;
- int i;
- if (getuid() != geteuid())
- return my_error (GPG_ERR_BUG);
+ if (process->terminated)
+ /* Already terminated. */
+ return 0;
- if ((ec = gnupg_access (pgmname, X_OK)))
- return gpg_err_make (default_errsource, ec);
+ pre_syscall ();
+ while ((pid = waitpid (process->pid, &status, hang? 0: WNOHANG))
+ == (pid_t)(-1) && errno == EINTR);
+ post_syscall ();
- pid = fork ();
if (pid == (pid_t)(-1))
{
- log_error (_("error forking process: %s\n"), strerror (errno));
- return my_error_from_syserror ();
+ ec = gpg_err_code_from_syserror ();
+ log_error (_("waiting for process %d to terminate failed: %s\n"),
+ (int)pid, gpg_strerror (ec));
}
- if (!pid)
+ else if (!pid)
{
- pid_t pid2;
-
- gcry_control (GCRYCTL_TERM_SECMEM);
- 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. */
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ }
+ else
+ {
+ process->terminated = 1;
+ process->wstatus = status;
+ ec = 0;
+ }
- if (envp)
- for (i=0; envp[i]; i++)
- putenv (xstrdup (envp[i]));
+ return ec;
+}
- do_exec (pgmname, argv, -1, -1, -1, NULL, 0);
+void
+gnupg_process_release (gnupg_process_t process)
+{
+ if (!process)
+ return;
- /*NOTREACHED*/
+ if (process->terminated)
+ {
+ gnupg_process_terminate (process);
+ gnupg_process_wait (process, 1);
}
- if (waitpid (pid, NULL, 0) == -1)
- log_error ("waitpid failed in gnupg_spawn_process_detached: %s",
- strerror (errno));
-
- return 0;
+ xfree (process);
}
-
-/* Kill a process; that is send an appropriate signal to the process.
- gnupg_wait_process must be called to actually remove the process
- from the system. An invalid PID is ignored. */
-void
-gnupg_kill_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang)
{
- if (pid != (pid_t)(-1))
+ gpg_err_code_t ec = 0;
+ int i;
+
+ for (i = 0; i < count; i++)
{
- kill (pid, SIGTERM);
+ 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..f63341e7c 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 0x600
#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
@@ -405,143 +409,145 @@ gnupg_close_pipe (int fd)
if (fd != -1)
close (fd);
}
+
+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 ();
+}
-/* Fork and exec the PGMNAME, see exechelp.h for details. */
-gpg_error_t
-gnupg_spawn_process (const char *pgmname, const char *argv[],
- int *except, unsigned int flags,
- estream_t *r_infp,
- estream_t *r_outfp,
- estream_t *r_errfp,
- pid_t *pid)
+static void
+post_syscall (void)
{
- gpg_error_t err;
- SECURITY_ATTRIBUTES sec_attr;
- PROCESS_INFORMATION pi =
- {
- NULL, /* Returns process handle. */
- 0, /* Returns primary thread handle. */
- 0, /* Returns pid. */
- 0 /* Returns tid. */
- };
- STARTUPINFOW si;
- int cr_flags;
- char *cmdline;
- wchar_t *wcmdline = NULL;
- wchar_t *wpgmname = NULL;
- HANDLE inpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
- HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
- HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
- estream_t infp = NULL;
- estream_t outfp = NULL;
- estream_t errfp = NULL;
- HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
- INVALID_HANDLE_VALUE,
- INVALID_HANDLE_VALUE};
- int i, rc;
- es_syshd_t syshd;
- gpg_err_source_t errsource = default_errsource;
- int nonblock = !!(flags & GNUPG_SPAWN_NONBLOCK);
+ if (post_syscall_func)
+ post_syscall_func ();
+}
- (void)except; /* Not yet used. */
- if (r_infp)
- *r_infp = NULL;
- if (r_outfp)
- *r_outfp = NULL;
- if (r_errfp)
- *r_errfp = NULL;
- *pid = (pid_t)(-1); /* Always required. */
+/*
+ * Check if STARTUPINFOEXW supports PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+ */
+static int
+check_windows_version (void)
+{
+ static int is_vista_or_later = -1;
+
+ OSVERSIONINFO osvi;
- if (r_infp)
+ if (is_vista_or_later == -1)
{
- if (create_inheritable_pipe (inpipe, INHERIT_READ))
- {
- err = gpg_err_make (errsource, GPG_ERR_GENERAL);
- log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
- return err;
- }
+ memset (&osvi,0,sizeof(osvi));
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ GetVersionEx (&osvi);
- syshd.type = ES_SYSHD_HANDLE;
- syshd.u.handle = inpipe[1];
- infp = es_sysopen (&syshd, nonblock? "w,nonblock" : "w");
- if (!infp)
- {
- err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
- log_error (_("error creating a stream for a pipe: %s\n"),
- gpg_strerror (err));
- CloseHandle (inpipe[0]);
- CloseHandle (inpipe[1]);
- inpipe[0] = inpipe[1] = INVALID_HANDLE_VALUE;
- return err;
- }
+ /* The feature is available on Vista or later. */
+ is_vista_or_later = (osvi.dwMajorVersion >= 6);
}
- if (r_outfp)
- {
- if (create_inheritable_pipe (outpipe, INHERIT_WRITE))
- {
- err = gpg_err_make (errsource, GPG_ERR_GENERAL);
- log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
- return err;
- }
+ return is_vista_or_later;
+}
- syshd.type = ES_SYSHD_HANDLE;
- syshd.u.handle = outpipe[0];
- outfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
- if (!outfp)
- {
- err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
- log_error (_("error creating a stream for a pipe: %s\n"),
- gpg_strerror (err));
- CloseHandle (outpipe[0]);
- CloseHandle (outpipe[1]);
- outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[1]);
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- return err;
- }
+
+static gpg_err_code_t
+spawn_detached (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;
+ BOOL ask_inherit = FALSE;
+
+ ec = gnupg_access (pgmname, X_OK);
+ if (ec)
+ {
+ xfree (cmdline);
+ return ec;
}
- if (r_errfp)
+ memset (&si, 0, sizeof si);
+
+ 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);
+
+ if (sca.inherit_hds)
{
- if (create_inheritable_pipe (errpipe, INHERIT_WRITE))
- {
- err = gpg_err_make (errsource, GPG_ERR_GENERAL);
- log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
- return err;
- }
+ SIZE_T attr_list_size = 0;
+ HANDLE hd[16];
+ HANDLE *hd_p = sca.inherit_hds;
+ int j = 0;
- syshd.type = ES_SYSHD_HANDLE;
- syshd.u.handle = errpipe[0];
- errfp = es_sysopen (&syshd, nonblock? "r,nonblock" : "r");
- if (!errfp)
+ if (hd_p)
{
- err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
- log_error (_("error creating a stream for a pipe: %s\n"),
- gpg_strerror (err));
- CloseHandle (errpipe[0]);
- CloseHandle (errpipe[1]);
- errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[0]);
- if (outpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[1]);
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- return err;
+ while (*hd_p != INVALID_HANDLE_VALUE)
+ if (j < DIM (hd))
+ hd[j++] = *hd_p++;
+ else
+ {
+ log_error ("Too much handles\n");
+ break;
+ }
}
+
+ if (j)
+ {
+ if (check_windows_version ())
+ {
+ InitializeProcThreadAttributeList (NULL, 1, 0, &attr_list_size);
+ si.lpAttributeList = xtrymalloc (attr_list_size);
+ if (si.lpAttributeList == NULL)
+ {
+ 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);
+ }
+
+ ask_inherit = TRUE;
+ }
}
/* Prepare security attributes. */
@@ -549,502 +555,683 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
- /* Build the command line. */
- err = build_w32_commandline (pgmname, argv, &cmdline);
- if (err)
- return err;
-
- if (inpipe[0] == INVALID_HANDLE_VALUE)
- nullhd[0] = ((flags & GNUPG_SPAWN_KEEP_STDIN)?
- GetStdHandle (STD_INPUT_HANDLE) : w32_open_null (0));
- if (outpipe[1] == INVALID_HANDLE_VALUE)
- nullhd[1] = ((flags & GNUPG_SPAWN_KEEP_STDOUT)?
- GetStdHandle (STD_OUTPUT_HANDLE) : w32_open_null (1));
- if (errpipe[1] == INVALID_HANDLE_VALUE)
- nullhd[2] = ((flags & GNUPG_SPAWN_KEEP_STDOUT)?
- GetStdHandle (STD_ERROR_HANDLE) : w32_open_null (1));
-
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_HIDE;
- si.hStdInput = inpipe[0] == INVALID_HANDLE_VALUE? nullhd[0] : inpipe[0];
- si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
- si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
+ /* 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
- | ((flags & GNUPG_SPAWN_DETACHED)? DETACHED_PROCESS : 0)
| GetPriorityClass (GetCurrentProcess ())
- | CREATE_SUSPENDED);
- /* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", */
- /* pgmname, cmdline); */
+ | CREATE_NEW_PROCESS_GROUP
+ | DETACHED_PROCESS);
+
/* Take care: CreateProcessW may modify wpgmname */
if (!(wpgmname = utf8_to_wchar (pgmname)))
- rc = 0;
+ ret = 0;
else if (!(wcmdline = utf8_to_wchar (cmdline)))
- rc = 0;
+ ret = 0;
else
- rc = CreateProcessW (wpgmname, /* Program to start. */
- wcmdline, /* Command line arguments. */
- &sec_attr, /* Process security attributes. */
- &sec_attr, /* Thread security attributes. */
- TRUE, /* Inherit handles. */
- cr_flags, /* Creation flags. */
- NULL, /* Environment. */
- NULL, /* Use current drive/directory. */
- &si, /* Startup information. */
- &pi /* Returns process information. */
- );
- if (!rc)
+ ret = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ 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: %s\n", w32_strerror (-1));
+ log_error ("CreateProcess(detached) failed: %d\n",
+ (int)GetLastError ());
xfree (wpgmname);
xfree (wcmdline);
xfree (cmdline);
- if (infp)
- es_fclose (infp);
- else if (inpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- if (outfp)
- es_fclose (outfp);
- else if (outpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[0]);
- if (outpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (errfp)
- es_fclose (errfp);
- else if (errpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (errpipe[0]);
- if (errpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (errpipe[1]);
- return gpg_err_make (errsource, GPG_ERR_GENERAL);
+ return GPG_ERR_GENERAL;
}
+ if (si.lpAttributeList)
+ DeleteProcThreadAttributeList (si.lpAttributeList);
xfree (wpgmname);
xfree (wcmdline);
xfree (cmdline);
- cmdline = NULL;
-
- /* Close the inherited handles to /dev/null. */
- for (i=0; i < DIM (nullhd); i++)
- if (nullhd[i] != INVALID_HANDLE_VALUE)
- CloseHandle (nullhd[i]);
- /* Close the inherited ends of the pipes. */
- if (inpipe[0] != INVALID_HANDLE_VALUE)
- CloseHandle (inpipe[0]);
- if (outpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (outpipe[1]);
- if (errpipe[1] != INVALID_HANDLE_VALUE)
- CloseHandle (errpipe[1]);
+ /* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
+ /* " dwProcessID=%d dwThreadId=%d\n", */
+ /* pi.hProcess, pi.hThread, */
+ /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
- /* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
- /* " dwProcessID=%d dwThreadId=%d\n", */
- /* pi.hProcess, pi.hThread, */
- /* (int) pi.dwProcessId, (int) pi.dwThreadId); */
- /* log_debug (" outfp=%p errfp=%p\n", outfp, errfp); */
+ /* Note: AllowSetForegroundWindow doesn't make sense for background
+ process. */
- /* 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 ((flags & GNUPG_SPAWN_RUN_ASFW))
- gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
-
- /* Process has been created suspended; resume it now. */
- ResumeThread (pi.hThread);
CloseHandle (pi.hThread);
-
- if (r_infp)
- *r_infp = infp;
- if (r_outfp)
- *r_outfp = outfp;
- if (r_errfp)
- *r_errfp = errfp;
-
- *pid = handle_to_pid (pi.hProcess);
+ CloseHandle (pi.hProcess);
return 0;
-
}
+void
+gnupg_spawn_helper (struct spawn_cb_arg *sca)
+{
+ HANDLE *user_except = sca->arg;
+ sca->inherit_hds = user_except;
+}
-/* Simplified version of gnupg_spawn_process. This function forks and
- then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
- and ERRFD to stderr (any of them may be -1 to connect them to
- /dev/null). The arguments for the process are expected in the NULL
- terminated array ARGV. The program name itself should not be
- included there. Calling gnupg_wait_process is required.
-
- Returns 0 on success or an error code. */
-gpg_error_t
-gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
- int infd, int outfd, int errfd, pid_t *pid)
+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_error_t err;
+ gpg_err_code_t ec;
+ gnupg_process_t process;
SECURITY_ATTRIBUTES sec_attr;
PROCESS_INFORMATION pi = { NULL, 0, 0, 0 };
- STARTUPINFOW si;
+ STARTUPINFOEXW si;
+ int cr_flags;
char *cmdline;
wchar_t *wcmdline = NULL;
wchar_t *wpgmname = NULL;
- int i, rc;
- HANDLE stdhd[3];
+ int ret;
+ HANDLE hd_in[2];
+ HANDLE hd_out[2];
+ HANDLE hd_err[2];
+ struct spawn_cb_arg sca;
+ int i;
+ BOOL ask_inherit = FALSE;
+
+ check_syscall_func ();
+
+ /* Build the command line. */
+ ec = build_w32_commandline (pgmname, argv, &cmdline);
+ if (ec)
+ return ec;
+
+ if ((flags & GNUPG_PROCESS_DETACHED))
+ {
+ if ((flags & GNUPG_PROCESS_STDFDS_SETTING))
+ {
+ xfree (cmdline);
+ return GPG_ERR_INV_FLAG;
+ }
+
+ /* In detached case, it must be no R_PROCESS. */
+ if (r_process)
+ {
+ xfree (cmdline);
+ return GPG_ERR_INV_ARG;
+ }
+
+ return spawn_detached (pgmname, cmdline, spawn_cb, spawn_cb_arg);
+ }
+
+ if (r_process)
+ *r_process = NULL;
+
+ 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_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_KEEP))
+ {
+ hd_in[0] = GetStdHandle (STD_INPUT_HANDLE);
+ hd_in[1] = INVALID_HANDLE_VALUE;
+ }
+ else
+ {
+ hd_in[0] = w32_open_null (0);
+ 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_KEEP))
+ {
+ hd_out[0] = INVALID_HANDLE_VALUE;
+ hd_out[1] = GetStdHandle (STD_OUTPUT_HANDLE);
+ }
+ else
+ {
+ hd_out[0] = INVALID_HANDLE_VALUE;
+ hd_out[1] = w32_open_null (1);
+ }
- /* Setup return values. */
- *pid = (pid_t)(-1);
+ 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_KEEP))
+ {
+ hd_err[0] = INVALID_HANDLE_VALUE;
+ hd_err[1] = GetStdHandle (STD_ERROR_HANDLE);
+ }
+ else
+ {
+ hd_err[0] = INVALID_HANDLE_VALUE;
+ hd_err[1] = w32_open_null (1);
+ }
+
+ memset (&si, 0, sizeof si);
+
+ 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;
+ }
+ }
+
+ if (j)
+ {
+ if (check_windows_version ())
+ {
+ 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_KEEP))
+ 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_KEEP))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ CloseHandle (hd_err[0]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || !(flags & GNUPG_PROCESS_STDERR_KEEP))
+ CloseHandle (hd_err[1]);
+ 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);
+ }
+ ask_inherit = TRUE;
+ }
+ }
/* Prepare security attributes. */
memset (&sec_attr, 0, sizeof sec_attr );
sec_attr.nLength = sizeof sec_attr;
sec_attr.bInheritHandle = FALSE;
- /* Build the command line. */
- err = build_w32_commandline (pgmname, argv, &cmdline);
- if (err)
- return err;
-
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
- si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
- stdhd[0] = infd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
- stdhd[1] = outfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
- stdhd[2] = errfd == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
- si.hStdInput = infd == -1? stdhd[0] : (void*)_get_osfhandle (infd);
- si.hStdOutput = outfd == -1? stdhd[1] : (void*)_get_osfhandle (outfd);
- si.hStdError = errfd == -1? stdhd[2] : (void*)_get_osfhandle (errfd);
-
-/* log_debug ("CreateProcess, path='%s' cmdline='%s'\n", pgmname, cmdline); */
- /* Take care: CreateProcessW may modify wpgmname */
+ /* 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)))
- rc = 0;
+ ret = 0;
else if (!(wcmdline = utf8_to_wchar (cmdline)))
- rc = 0;
+ ret = 0;
else
- rc = CreateProcessW (wpgmname, /* Program to start. */
- wcmdline, /* Command line arguments. */
- &sec_attr, /* Process security attributes. */
- &sec_attr, /* Thread security attributes. */
- TRUE, /* Inherit handles. */
- (CREATE_DEFAULT_ERROR_MODE
- | GetPriorityClass (GetCurrentProcess ())
- | CREATE_SUSPENDED | DETACHED_PROCESS),
- NULL, /* Environment. */
- NULL, /* Use current drive/directory. */
- &si, /* Startup information. */
- &pi /* Returns process information. */
- );
- if (!rc)
+ ret = CreateProcessW (wpgmname, /* Program to start. */
+ wcmdline, /* Command line arguments. */
+ &sec_attr, /* Process security attributes. */
+ &sec_attr, /* Thread security attributes. */
+ 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));
+ strerror (errno));
else
- log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
- err = my_error (GPG_ERR_GENERAL);
+ log_error ("CreateProcess failed: ec=%d\n",
+ (int)GetLastError ());
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || !(flags & GNUPG_PROCESS_STDIN_KEEP))
+ 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_KEEP))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE))
+ CloseHandle (hd_err[0]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || !(flags & GNUPG_PROCESS_STDERR_KEEP))
+ CloseHandle (hd_err[1]);
+ xfree (wpgmname);
+ xfree (wcmdline);
+ xfree (process);
+ xfree (cmdline);
+ return GPG_ERR_GENERAL;
}
- else
- err = 0;
+
+ if (si.lpAttributeList)
+ DeleteProcThreadAttributeList (si.lpAttributeList);
xfree (wpgmname);
xfree (wcmdline);
xfree (cmdline);
- for (i=0; i < 3; i++)
- if (stdhd[i] != INVALID_HANDLE_VALUE)
- CloseHandle (stdhd[i]);
- if (err)
- return err;
-/* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
-/* " dwProcessID=%d dwThreadId=%d\n", */
-/* pi.hProcess, pi.hThread, */
-/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
+ if ((flags & GNUPG_PROCESS_STDIN_PIPE)
+ || !(flags & GNUPG_PROCESS_STDIN_KEEP))
+ CloseHandle (hd_in[0]);
+ if ((flags & GNUPG_PROCESS_STDOUT_PIPE)
+ || !(flags & GNUPG_PROCESS_STDOUT_KEEP))
+ CloseHandle (hd_out[1]);
+ if ((flags & GNUPG_PROCESS_STDERR_PIPE)
+ || !(flags & GNUPG_PROCESS_STDERR_KEEP))
+ 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 ();
- *pid = handle_to_pid (pi.hProcess);
- return 0;
+ 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;
+ }
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_process (const char *pgmname, pid_t pid, int hang, int *r_exitcode)
+ 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)
{
- return gnupg_wait_processes (&pgmname, &pid, 1, hang, r_exitcode);
+ 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;
}
-/* See exechelp.h for a description. */
-gpg_error_t
-gnupg_wait_processes (const char **pgmnames, pid_t *pids, size_t count,
- int hang, int *r_exitcodes)
+static gpg_err_code_t
+process_kill (gnupg_process_t process, unsigned int exitcode)
{
gpg_err_code_t ec = 0;
- size_t i;
- HANDLE *procs;
- int code;
- procs = xtrycalloc (count, sizeof *procs);
- if (procs == NULL)
- return my_error_from_syserror ();
+ pre_syscall ();
+ if (TerminateProcess (process->hProcess, exitcode))
+ ec = gpg_err_code_from_syserror ();
+ post_syscall ();
+ return ec;
+}
- for (i = 0; i < count; i++)
+static gpg_err_code_t
+process_vctl (gnupg_process_t process, unsigned int request, va_list arg_ptr)
+{
+ switch (request)
{
- if (r_exitcodes)
- r_exitcodes[i] = -1;
+ case GNUPG_PROCESS_NOP:
+ return 0;
- if (pids[i] == (pid_t)(-1))
- return my_error (GPG_ERR_INV_VALUE);
+ case GNUPG_PROCESS_GET_PROC_ID:
+ {
+ int *r_id = va_arg (arg_ptr, int *);
- procs[i] = pid_to_handle (pids[i]);
- }
+ if (r_id == NULL)
+ return GPG_ERR_INV_VALUE;
- /* FIXME: We should do a pth_waitpid here. However this has not yet
- been implemented. A special W32 pth system call would even be
- better. */
- code = WaitForMultipleObjects (count, procs, TRUE, hang? INFINITE : 0);
- switch (code)
- {
- case WAIT_TIMEOUT:
- ec = GPG_ERR_TIMEOUT;
- goto leave;
+ *r_id = (int)GetProcessId (process->hProcess);
+ return 0;
+ }
- case WAIT_FAILED:
- log_error (_("waiting for processes to terminate failed: %s\n"),
- w32_strerror (-1));
- ec = GPG_ERR_GENERAL;
- goto leave;
+ case GNUPG_PROCESS_GET_EXIT_ID:
+ {
+ int *r_exit_status = va_arg (arg_ptr, int *);
+ unsigned long exit_code;
- case WAIT_OBJECT_0:
- for (i = 0; i < count; i++)
- {
- DWORD exc;
+ *r_exit_status = -1;
- if (! GetExitCodeProcess (procs[i], &exc))
- {
- log_error (_("error getting exit code of process %d: %s\n"),
- (int) pids[i], w32_strerror (-1) );
- ec = GPG_ERR_GENERAL;
- }
- else if (exc)
- {
- if (!r_exitcodes)
- log_error (_("error running '%s': exit status %d\n"),
- pgmnames[i], (int)exc);
- else
- r_exitcodes[i] = (int)exc;
- ec = GPG_ERR_GENERAL;
- }
- else
- {
- if (r_exitcodes)
- r_exitcodes[i] = 0;
- }
- }
- break;
+ 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:
- log_error ("WaitForMultipleObjects returned unexpected "
- "code %d\n", code);
- ec = GPG_ERR_GENERAL;
break;
}
- leave:
- return gpg_err_make (GPG_ERR_SOURCE_DEFAULT, ec);
+ return GPG_ERR_UNKNOWN_COMMAND;
}
-
-
-void
-gnupg_release_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_ctl (gnupg_process_t process, unsigned int request, ...)
{
- if (pid != (pid_t)INVALID_HANDLE_VALUE)
- {
- HANDLE process = (HANDLE)pid;
+ va_list arg_ptr;
+ gpg_err_code_t ec;
- CloseHandle (process);
- }
+ va_start (arg_ptr, request);
+ ec = process_vctl (process, request, arg_ptr);
+ va_end (arg_ptr);
+ return ec;
}
-
-/* Spawn a new process and immediately detach from it. The name of
- the program to exec is PGMNAME and its arguments are in ARGV (the
- programname is automatically passed as first argument).
- Environment strings in ENVP are set. An error is returned if
- pgmname is not executable; to make this work it is necessary to
- provide an absolute file name. All standard file descriptors are
- connected to /dev/null. */
-gpg_error_t
-gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
- const char *envp[] )
+gpg_err_code_t
+gnupg_process_wait (gnupg_process_t process, int hang)
{
- gpg_error_t err;
- SECURITY_ATTRIBUTES sec_attr;
- PROCESS_INFORMATION pi =
- {
- NULL, /* Returns process handle. */
- 0, /* Returns primary thread handle. */
- 0, /* Returns pid. */
- 0 /* Returns tid. */
- };
- STARTUPINFOW si;
- int cr_flags;
- char *cmdline;
- wchar_t *wcmdline = NULL;
- wchar_t *wpgmname = NULL;
- BOOL in_job = FALSE;
gpg_err_code_t ec;
- int rc;
- int jobdebug;
+ int code;
- /* We don't use ENVP. */
- (void)envp;
+ if (process->hProcess == INVALID_HANDLE_VALUE)
+ return 0;
- cmdline = getenv ("GNUPG_EXEC_DEBUG_FLAGS");
- jobdebug = (cmdline && (atoi (cmdline) & 1));
+ pre_syscall ();
+ code = WaitForSingleObject (process->hProcess, hang? INFINITE : 0);
+ post_syscall ();
- if ((ec = gnupg_access (pgmname, X_OK)))
- return gpg_err_make (default_errsource, ec);
+ switch (code)
+ {
+ case WAIT_TIMEOUT:
+ ec = GPG_ERR_TIMEOUT; /* Still running. */
+ break;
- /* Prepare security attributes. */
- memset (&sec_attr, 0, sizeof sec_attr );
- sec_attr.nLength = sizeof sec_attr;
- sec_attr.bInheritHandle = FALSE;
+ case WAIT_FAILED:
+ log_error (_("waiting for process to terminate failed: ec=%d\n"),
+ (int)GetLastError ());
+ ec = GPG_ERR_GENERAL;
+ break;
- /* Build the command line. */
- err = build_w32_commandline (pgmname, argv, &cmdline);
- if (err)
- return err;
+ case WAIT_OBJECT_0:
+ process->terminated = 1;
+ ec = 0;
+ break;
- /* Start the process. */
- memset (&si, 0, sizeof si);
- si.cb = sizeof (si);
- si.dwFlags = STARTF_USESHOWWINDOW;
- si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
+ default:
+ log_debug ("WaitForSingleObject returned unexpected code %d\n", code);
+ ec = GPG_ERR_GENERAL;
+ break;
+ }
- cr_flags = (CREATE_DEFAULT_ERROR_MODE
- | GetPriorityClass (GetCurrentProcess ())
- | CREATE_NEW_PROCESS_GROUP
- | DETACHED_PROCESS);
+ return ec;
+}
- /* Check if we were spawned as part of a Job.
- * In a job we need to add CREATE_BREAKAWAY_FROM_JOB
- * to the cr_flags, otherwise our child processes
- * are killed when we terminate. */
- if (!IsProcessInJob (GetCurrentProcess(), NULL, &in_job))
- {
- log_error ("IsProcessInJob() failed: %s\n", w32_strerror (-1));
- in_job = FALSE;
- }
+gpg_err_code_t
+gnupg_process_terminate (gnupg_process_t process)
+{
+ return process_kill (process, 1);
+}
- if (in_job)
- {
- /* Only try to break away from job if it is allowed, otherwise
- * CreateProcess() would fail with an "Access is denied" error. */
- JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
- if (!QueryInformationJobObject (NULL, JobObjectExtendedLimitInformation,
- &info, sizeof info, NULL))
- {
- log_error ("QueryInformationJobObject() failed: %s\n",
- w32_strerror (-1));
- }
- else if ((info.BasicLimitInformation.LimitFlags &
- JOB_OBJECT_LIMIT_BREAKAWAY_OK))
- {
- if (jobdebug)
- log_debug ("Using CREATE_BREAKAWAY_FROM_JOB flag\n");
- cr_flags |= CREATE_BREAKAWAY_FROM_JOB;
- }
- else if ((info.BasicLimitInformation.LimitFlags &
- JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK))
- {
- /* The child process should automatically detach from the job. */
- if (jobdebug)
- log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag; "
- "JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK is set\n");
- }
- else
- {
- /* It seems that the child process must remain in the job.
- * This is not necessarily an error, although it can cause premature
- * termination of the child process when the job is closed. */
- if (jobdebug)
- log_debug ("Not using CREATE_BREAKAWAY_FROM_JOB flag\n");
- }
- }
- else
- {
- if (jobdebug)
- log_debug ("Process is not in a Job\n");
- }
+void
+gnupg_process_release (gnupg_process_t process)
+{
+ if (!process)
+ return;
- /* log_debug ("CreateProcess(detached), path='%s' cmdline='%s'\n", */
- /* pgmname, cmdline); */
- /* Take care: CreateProcessW may modify wpgmname */
- if (!(wpgmname = utf8_to_wchar (pgmname)))
- rc = 0;
- else if (!(wcmdline = utf8_to_wchar (cmdline)))
- rc = 0;
- else
- rc = CreateProcessW (wpgmname, /* Program to start. */
- wcmdline, /* Command line arguments. */
- &sec_attr, /* Process security attributes. */
- &sec_attr, /* Thread security attributes. */
- FALSE, /* Inherit handles. */
- cr_flags, /* Creation flags. */
- NULL, /* Environment. */
- NULL, /* Use current drive/directory. */
- &si, /* Startup information. */
- &pi /* Returns process information. */
- );
- if (!rc)
+ if (process->terminated)
{
- if (!wpgmname || !wcmdline)
- log_error ("CreateProcess failed (utf8_to_wchar): %s\n",
- strerror (errno));
- else
- log_error ("CreateProcess(detached) failed: %s\n", w32_strerror (-1));
- xfree (wpgmname);
- xfree (wcmdline);
- xfree (cmdline);
- return my_error (GPG_ERR_GENERAL);
+ gnupg_process_terminate (process);
+ gnupg_process_wait (process, 1);
}
- xfree (wpgmname);
- xfree (wcmdline);
- xfree (cmdline);
- cmdline = NULL;
-
-/* log_debug ("CreateProcess(detached) ready: hProcess=%p hThread=%p" */
-/* " dwProcessID=%d dwThreadId=%d\n", */
-/* pi.hProcess, pi.hThread, */
-/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
- CloseHandle (pi.hThread);
- CloseHandle (pi.hProcess);
-
- return 0;
+ CloseHandle (process->hProcess);
+ xfree (process);
}
-
-/* Kill a process; that is send an appropriate signal to the process.
- gnupg_wait_process must be called to actually remove the process
- from the system. An invalid PID is ignored. */
-void
-gnupg_kill_process (pid_t pid)
+gpg_err_code_t
+gnupg_process_wait_list (gnupg_process_t *process_list, int count, int hang)
{
- if (pid != (pid_t) INVALID_HANDLE_VALUE)
+ gpg_err_code_t ec = 0;
+ int i;
+
+ for (i = 0; i < count; i++)
{
- HANDLE process = (HANDLE) pid;
+ if (process_list[i]->terminated)
+ continue;
- /* Arbitrary error code. */
- TerminateProcess (process, 1);
+ 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..0370b23a4 100644
--- a/common/exechelp.h
+++ b/common/exechelp.h
@@ -73,140 +73,103 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
void gnupg_close_pipe (int fd);
-#define GNUPG_SPAWN_NONBLOCK 16
-#define GNUPG_SPAWN_RUN_ASFW 64
-#define GNUPG_SPAWN_DETACHED 128
-#define GNUPG_SPAWN_KEEP_STDIN 256
-#define GNUPG_SPAWN_KEEP_STDOUT 512
-#define GNUPG_SPAWN_KEEP_STDERR 1024
-
-/* Fork and exec the program PGMNAME.
-
- If R_INFP is NULL connect stdin of the new process to /dev/null; if
- it is not NULL store the address of a pointer to a new estream
- there. If R_OUTFP is NULL connect stdout of the new process to
- /dev/null; if it is not NULL store the address of a pointer to a
- new estream there. If R_ERRFP is NULL connect stderr of the new
- process to /dev/null; if it is not NULL store the address of a
- pointer to a new estream there. On success the pid of the new
- process is stored at PID. On error -1 is stored at PID and if
- R_OUTFP or R_ERRFP are not NULL, NULL is stored there.
-
- The arguments for the process are expected in the NULL terminated
- array ARGV. The program name itself should not be included there.
- If PREEXEC is not NULL, the given function will be called right
- before the exec.
-
- IF EXCEPT is not NULL, it is expected to be an ordered list of file
- descriptors, terminated by an entry with the value (-1). These
- file descriptors won't be closed before spawning a new program.
-
- Returns 0 on success or an error code. Calling gnupg_wait_process
- and gnupg_release_process is required if the function succeeded.
-
- FLAGS is a bit vector:
-
- GNUPG_SPAWN_NONBLOCK
- If set the two output streams are created in non-blocking
- mode and the input stream is switched to non-blocking mode.
- This is merely a convenience feature because the caller
- could do the same with gpgrt_set_nonblock. Does not yet
- work for Windows.
-
- GNUPG_SPAWN_DETACHED
- If set the process will be started as a background process.
- This flag is only useful under W32 (but not W32CE) systems,
- so that no new console is created and pops up a console
- window when starting the server. Does not work on W32CE.
-
- GNUPG_SPAWN_RUN_ASFW
- On W32 (but not on W32CE) run AllowSetForegroundWindow for
- the child. Note that due to unknown problems this actually
- allows SetForegroundWindow for all children of this process.
-
- GNUPG_SPAWN_KEEP_STDIN
- GNUPG_SPAWN_KEEP_STDOUT
- GNUPG_SPAWN_KEEP_STDERR
- Do not assign /dev/null to a non-required standard file
- descriptor.
-
- */
-gpg_error_t
-gnupg_spawn_process (const char *pgmname, const char *argv[],
- int *execpt, unsigned int flags,
- estream_t *r_infp,
- estream_t *r_outfp,
- estream_t *r_errfp,
- pid_t *pid);
-
-
-/* Simplified version of gnupg_spawn_process. This function forks and
- then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
- and ERRFD to stderr (any of them may be -1 to connect them to
- /dev/null). The arguments for the process are expected in the NULL
- terminated array ARGV. The program name itself should not be
- included there. Calling gnupg_wait_process and
- gnupg_release_process is required. Returns 0 on success or an
- error code. */
-gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
- const char *argv[],
- int infd, int outfd, int errfd,
- pid_t *pid);
-
-
-/* If HANG is true, waits for the process identified by PID to exit;
- if HANG is false, checks whether the process has terminated.
- PGMNAME should be the same as supplied to the spawn function and is
- only used for diagnostics. Return values:
-
- 0
- The process exited successful. 0 is stored at R_EXITCODE.
-
- GPG_ERR_GENERAL
- The process exited without success. The exit code of process
- is then stored at R_EXITCODE. An exit code of -1 indicates
- that the process terminated abnormally (e.g. due to a signal).
-
- GPG_ERR_TIMEOUT
- The process is still running (returned only if HANG is false).
-
- GPG_ERR_INV_VALUE
- An invalid PID has been specified.
-
- Other error codes may be returned as well. Unless otherwise noted,
- -1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL
- if the exit code is not required (in that case an error message will
- be printed). Note that under Windows PID is not the process id but
- the handle of the process. */
-gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang,
- int *r_exitcode);
-
-/* Like gnupg_wait_process, but for COUNT processes. */
-gpg_error_t gnupg_wait_processes (const char **pgmnames, pid_t *pids,
- size_t count, int hang, int *r_exitcodes);
-
-
-/* Kill a process; that is send an appropriate signal to the process.
- gnupg_wait_process must be called to actually remove the process
- from the system. An invalid PID is ignored. */
-void gnupg_kill_process (pid_t pid);
-
-/* Release the process identified by PID. This function is actually
- only required for Windows but it does not harm to always call it.
- It is a nop if PID is invalid. */
-void gnupg_release_process (pid_t pid);
-
-
-/* Spawn a new process and immediately detach from it. The name of
- the program to exec is PGMNAME and its arguments are in ARGV (the
- programname is automatically passed as first argument).
- Environment strings in ENVP are set. An error is returned if
- pgmname is not executable; to make this work it is necessary to
- provide an absolute file name. */
-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 allow_foreground_window;
+ void *arg;
+};
+#endif
+#else
+struct spawn_cb_arg {
+ int fds[3];
+ int *except_fds;
+ void *arg;
+};
+#endif
+
+#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_KEEP (1 << 12)
+#define GNUPG_PROCESS_STDOUT_KEEP (1 << 13)
+#define GNUPG_PROCESS_STDERR_KEEP (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_KEEP \
+ | GNUPG_PROCESS_STDOUT_KEEP | GNUPG_PROCESS_STDERR_KEEP)
+
+#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_PROC_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..3505c25f1 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
+ : 0)
+ | 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/common/iobuf.c b/common/iobuf.c
index 161769a35..fb87ff65d 100644
--- a/common/iobuf.c
+++ b/common/iobuf.c
@@ -166,7 +166,9 @@ block_filter_ctx_t;
/* Local prototypes. */
static int underflow (iobuf_t a, int clear_pending_eof);
static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
-static int translate_file_handle (int fd, int for_write);
+static gnupg_fd_t translate_file_handle (int fd, int for_write);
+static iobuf_t do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open);
+
/* Sends any pending data to the filter's FILTER function. Note: this
works on the filter and not on the whole pipeline. That is,
@@ -1448,8 +1450,8 @@ do_open (const char *fname, int special_filenames,
return NULL;
else if (special_filenames
&& (fd = check_special_filename (fname, 0, 1)) != -1)
- return iobuf_fdopen (translate_file_handle (fd, use == IOBUF_INPUT ? 0 : 1),
- opentype);
+ return do_iobuf_fdopen (translate_file_handle (fd, use == IOBUF_INPUT
+ ? 0 : 1), opentype, 0);
else
{
if (use == IOBUF_INPUT)
@@ -1497,22 +1499,19 @@ iobuf_openrw (const char *fname)
static iobuf_t
-do_iobuf_fdopen (int fd, const char *mode, int keep_open)
+do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open)
{
iobuf_t a;
- gnupg_fd_t fp;
file_filter_ctx_t *fcx;
size_t len = 0;
- fp = INT2FD (fd);
-
a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
iobuf_buffer_size);
fcx = xmalloc (sizeof *fcx + 20);
fcx->fp = fp;
fcx->print_only_name = 1;
fcx->keep_open = keep_open;
- sprintf (fcx->fname, "[fd %d]", fd);
+ sprintf (fcx->fname, "[fd %d]", (int)(intptr_t)fp);
a->filter = file_filter;
a->filter_ov = fcx;
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
@@ -1527,13 +1526,15 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open)
iobuf_t
iobuf_fdopen (int fd, const char *mode)
{
- return do_iobuf_fdopen (fd, mode, 0);
+ gnupg_fd_t fp = INT2FD (fd);
+ return do_iobuf_fdopen (fp, mode, 0);
}
iobuf_t
iobuf_fdopen_nc (int fd, const char *mode)
{
- return do_iobuf_fdopen (fd, mode, 1);
+ gnupg_fd_t fp = INT2FD (fd);
+ return do_iobuf_fdopen (fp, mode, 1);
}
@@ -2948,34 +2949,34 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
return nbytes;
}
-static int
+static gnupg_fd_t
translate_file_handle (int fd, int for_write)
{
#if defined(HAVE_W32_SYSTEM)
{
- int x;
+ gnupg_fd_t x;
(void)for_write;
if (fd == 0)
- x = (int) GetStdHandle (STD_INPUT_HANDLE);
+ x = GetStdHandle (STD_INPUT_HANDLE);
else if (fd == 1)
- x = (int) GetStdHandle (STD_OUTPUT_HANDLE);
+ x = GetStdHandle (STD_OUTPUT_HANDLE);
else if (fd == 2)
- x = (int) GetStdHandle (STD_ERROR_HANDLE);
+ x = GetStdHandle (STD_ERROR_HANDLE);
else
- x = fd;
+ x = (gnupg_fd_t)(intptr_t)fd;
- if (x == -1)
+ if (x == INVALID_HANDLE_VALUE)
log_debug ("GetStdHandle(%d) failed: ec=%d\n",
fd, (int) GetLastError ());
- fd = x;
+ return x;
}
#else
(void)for_write;
-#endif
return fd;
+#endif
}
@@ -3028,3 +3029,123 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
}
}
}
+
+
+/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
+ * packet. LEN should be at least 6. */
+static int
+is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
+{
+ int c, ctb, pkttype;
+ int lenbytes;
+
+ ctb = *buf++; len--;
+ if (!(ctb & 0x80))
+ return 0; /* Invalid packet. */
+
+ if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
+ {
+ pkttype = (ctb & 0x3f);
+ if (!len)
+ return 0; /* Expected first length octet missing. */
+ c = *buf++; len--;
+ if (c < 192)
+ ;
+ else if (c < 224)
+ {
+ if (!len)
+ return 0; /* Expected second length octet missing. */
+ }
+ else if (c == 255)
+ {
+ if (len < 4)
+ return 0; /* Expected length octets missing */
+ }
+ }
+ else /* Old style CTB. */
+ {
+ pkttype = (ctb>>2)&0xf;
+ lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
+ if (len < lenbytes)
+ return 0; /* Not enough length bytes. */
+ }
+
+ return (pkttype == 8);
+}
+
+
+/*
+ * Check if the file is compressed, by peeking the iobuf. You need to
+ * pass the iobuf with INP. Returns true if the buffer seems to be
+ * compressed.
+ */
+int
+is_file_compressed (iobuf_t inp)
+{
+ int i;
+ char buf[32];
+ int buflen;
+
+ struct magic_compress_s
+ {
+ byte len;
+ byte extchk;
+ byte magic[5];
+ } magic[] =
+ {
+ { 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
+ { 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
+ { 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
+ { 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
+ { 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
+ { 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */
+ };
+
+ if (!inp)
+ return 0;
+
+ for ( ; inp->chain; inp = inp->chain )
+ ;
+
+ buflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof buf, buf);
+ if (buflen < 0)
+ {
+ buflen = 0;
+ log_debug ("peeking at input failed\n");
+ }
+
+ if ( buflen < 6 )
+ {
+ return 0; /* Too short to check - assume uncompressed. */
+ }
+
+ for ( i = 0; i < DIM (magic); i++ )
+ {
+ if (!memcmp( buf, magic[i].magic, magic[i].len))
+ {
+ switch (magic[i].extchk)
+ {
+ case 0:
+ return 1; /* Is compressed. */
+ case 1:
+ if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
+ return 1; /* JFIF: this likely a compressed JPEG. */
+ break;
+ case 2:
+ if (buflen > 8
+ && buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
+ return 1; /* This is a PNG. */
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
+ {
+ return 1; /* Already compressed. */
+ }
+
+ return 0; /* Not detected as compressed. */
+}
diff --git a/common/iobuf.h b/common/iobuf.h
index 751ae73c3..04e6b4421 100644
--- a/common/iobuf.h
+++ b/common/iobuf.h
@@ -625,6 +625,9 @@ void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len);
from the following filter (which may or may not return EOF). */
void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
+/* Check if the file is compressed, by peeking the iobuf. */
+int is_file_compressed (iobuf_t inp);
+
#define iobuf_where(a) "[don't know]"
/* Each time a filter is allocated (via iobuf_alloc()), a
diff --git a/common/miscellaneous.c b/common/miscellaneous.c
index f19cc539d..1a090b1f5 100644
--- a/common/miscellaneous.c
+++ b/common/miscellaneous.c
@@ -415,112 +415,6 @@ decode_c_string (const char *src)
}
-/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
- * packet. LEN should be at least 6. */
-static int
-is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
-{
- int c, ctb, pkttype;
- int lenbytes;
-
- ctb = *buf++; len--;
- if (!(ctb & 0x80))
- return 0; /* Invalid packet. */
-
- if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
- {
- pkttype = (ctb & 0x3f);
- if (!len)
- return 0; /* Expected first length octet missing. */
- c = *buf++; len--;
- if (c < 192)
- ;
- else if (c < 224)
- {
- if (!len)
- return 0; /* Expected second length octet missing. */
- }
- else if (c == 255)
- {
- if (len < 4)
- return 0; /* Expected length octets missing */
- }
- }
- else /* Old style CTB. */
- {
- pkttype = (ctb>>2)&0xf;
- lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
- if (len < lenbytes)
- return 0; /* Not enough length bytes. */
- }
-
- return (pkttype == 8);
-}
-
-
-
-/*
- * Check if the file is compressed. You need to pass the first bytes
- * of the file as (BUF,BUFLEN). Returns true if the buffer seems to
- * be compressed.
- */
-int
-is_file_compressed (const byte *buf, unsigned int buflen)
-{
- int i;
-
- struct magic_compress_s
- {
- byte len;
- byte extchk;
- byte magic[5];
- } magic[] =
- {
- { 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
- { 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
- { 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
- { 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
- { 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
- { 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */
- };
-
- if ( buflen < 6 )
- {
- return 0; /* Too short to check - assume uncompressed. */
- }
-
- for ( i = 0; i < DIM (magic); i++ )
- {
- if (!memcmp( buf, magic[i].magic, magic[i].len))
- {
- switch (magic[i].extchk)
- {
- case 0:
- return 1; /* Is compressed. */
- case 1:
- if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
- return 1; /* JFIF: this likely a compressed JPEG. */
- break;
- case 2:
- if (buflen > 8
- && buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
- return 1; /* This is a PNG. */
- break;
- default:
- break;
- }
- }
- }
-
- if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
- {
- return 1; /* Already compressed. */
- }
-
- return 0; /* Not detected as compressed. */
-}
-
-
/* Try match against each substring of multistr, delimited by | */
int
match_multistr (const char *multistr,const char *match)
diff --git a/common/sysutils.c b/common/sysutils.c
index f8e6d86fc..fc60af49c 100644
--- a/common/sysutils.c
+++ b/common/sysutils.c
@@ -558,17 +558,15 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
}
/* This is the same as translate_sys2libc_fd but takes an integer
- which is assumed to be such an system handle. On WindowsCE the
- passed FD is a rendezvous ID and the function finishes the pipe
- creation. */
+ which is assumed to be such an system handle. */
int
translate_sys2libc_fd_int (int fd, int for_write)
{
#ifdef HAVE_W32_SYSTEM
if (fd <= 2)
- return fd; /* Do not do this for error, stdin, stdout, stderr. */
+ return fd; /* Do not do this for stdin, stdout, and stderr. */
- return translate_sys2libc_fd ((void*)fd, for_write);
+ return translate_sys2libc_fd ((void*)(intptr_t)fd, for_write);
#else
(void)for_write;
return fd;
@@ -576,6 +574,70 @@ translate_sys2libc_fd_int (int fd, int for_write)
}
+/*
+ * Parse the string representation of a file reference (file handle on
+ * Windows or file descriptor on POSIX) in FDSTR. The string
+ * representation may be either of folllowing:
+
+ * (1) 0, 1, or 2 which means stdin, stdout, and stderr, respectively.
+ * (2) Integer representation (by %d of printf).
+ * (3) Hex representation which starts as "0x".
+ *
+ * Then, fill R_SYSHD, according to the value of a file reference.
+ *
+ */
+gpg_error_t
+gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd)
+{
+ int fd = -1;
+#ifdef HAVE_W32_SYSTEM
+ gnupg_fd_t hd;
+ char *endptr;
+ int base;
+
+ if (!strcmp (fdstr, "0"))
+ fd = 0;
+ else if (!strcmp (fdstr, "1"))
+ fd = 1;
+ else if (!strcmp (fdstr, "2"))
+ fd = 2;
+
+ if (fd >= 0)
+ {
+ r_syshd->type = ES_SYSHD_FD;
+ r_syshd->u.fd = fd;
+ return 0;
+ }
+
+ if (!strncmp (fdstr, "0x", 2))
+ {
+ base = 16;
+ fdstr += 2;
+ }
+ else
+ base = 10;
+
+ gpg_err_set_errno (0);
+#ifdef _WIN64
+ hd = (gnupg_fd_t)strtoll (fdstr, &endptr, base);
+#else
+ hd = (gnupg_fd_t)strtol (fdstr, &endptr, base);
+#endif
+ if (errno != 0 || endptr == fdstr || *endptr != '\0')
+ return gpg_error (GPG_ERR_INV_ARG);
+
+ r_syshd->type = ES_SYSHD_HANDLE;
+ r_syshd->u.handle = hd;
+ return 0;
+#else
+ fd = atoi (fdstr);
+ r_syshd->type = ES_SYSHD_FD;
+ r_syshd->u.fd = fd;
+ return 0;
+#endif
+}
+
+
/* Check whether FNAME has the form "-&nnnn", where N is a non-zero
* number. Returns this number or -1 if it is not the case. If the
* caller wants to use the file descriptor for writing FOR_WRITE shall
@@ -593,8 +655,27 @@ check_special_filename (const char *fname, int for_write, int notranslate)
for (i=0; digitp (fname+i); i++ )
;
if (!fname[i])
- return notranslate? atoi (fname)
- /**/ : translate_sys2libc_fd_int (atoi (fname), for_write);
+ {
+ if (notranslate)
+ return atoi (fname);
+ else
+ {
+ es_syshd_t syshd;
+
+ if (gnupg_parse_fdstr (fname, &syshd))
+ return -1;
+
+#ifdef HAVE_W32_SYSTEM
+ if (syshd.type == ES_SYSHD_FD)
+ return syshd.u.fd;
+ else
+ return translate_sys2libc_fd ((gnupg_fd_t)syshd.u.handle, for_write);
+#else
+ (void)for_write;
+ return syshd.u.fd;
+#endif
+ }
+ }
}
return -1;
}
@@ -1152,6 +1233,19 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
return setenv (name, value, overwrite);
#else /*!HAVE_SETENV*/
if (! getenv (name) || overwrite)
+#if defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+ {
+ int e = _putenv_s (name, value);
+
+ if (e)
+ {
+ gpg_err_set_errno (e);
+ return -1;
+ }
+ else
+ return 0;
+ }
+#else
{
char *buf;
@@ -1169,6 +1263,7 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
# endif
return putenv (buf);
}
+#endif /*!HAVE_W32_SYSTEM*/
return 0;
#endif /*!HAVE_SETENV*/
}
@@ -1193,6 +1288,18 @@ gnupg_unsetenv (const char *name)
#ifdef HAVE_UNSETENV
return unsetenv (name);
+#elif defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
+ {
+ int e = _putenv_s (name, "");
+
+ if (e)
+ {
+ gpg_err_set_errno (e);
+ return -1;
+ }
+ else
+ return 0;
+ }
#else /*!HAVE_UNSETENV*/
{
char *buf;
diff --git a/common/sysutils.h b/common/sysutils.h
index a78a81c64..50e59175f 100644
--- a/common/sysutils.h
+++ b/common/sysutils.h
@@ -74,6 +74,7 @@ void gnupg_sleep (unsigned int seconds);
void gnupg_usleep (unsigned int usecs);
int translate_sys2libc_fd (gnupg_fd_t fd, int for_write);
int translate_sys2libc_fd_int (int fd, int for_write);
+gpg_error_t gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd);
int check_special_filename (const char *fname, int for_write, int notranslate);
FILE *gnupg_tmpfile (void);
void gnupg_reopen_std (const char *pgmname);
diff --git a/common/t-exechelp.c b/common/t-exechelp.c
index 3bf082bbb..2179ef2a0 100644
--- a/common/t-exechelp.c
+++ b/common/t-exechelp.c
@@ -29,7 +29,7 @@
static int verbose;
-
+#ifndef HAVE_W32_SYSTEM
static void
print_open_fds (int *array)
{
@@ -169,20 +169,168 @@ test_close_all_fds (void)
}
}
+#endif
+
+static char buff12k[1024*12];
+static char buff4k[1024*4];
+
+static void
+run_server (void)
+{
+ estream_t fp;
+ int i;
+ char *p;
+ unsigned int len;
+ int ret;
+ es_syshd_t syshd;
+ size_t n;
+ off_t o;
+
+#ifdef HAVE_W32_SYSTEM
+ syshd.type = ES_SYSHD_HANDLE;
+ syshd.u.handle = (HANDLE)_get_osfhandle (1);
+#else
+ syshd.type = ES_SYSHD_FD;
+ syshd.u.fd = 1;
+#endif
+
+ fp = es_sysopen_nc (&syshd, "w");
+ if (fp == NULL)
+ {
+ fprintf (stderr, "es_fdopen failed\n");
+ exit (1);
+ }
+
+ /* Fill the buffer by ASCII chars. */
+ p = buff12k;
+ for (i = 0; i < sizeof (buff12k); i++)
+ if ((i % 64) == 63)
+ *p++ = '\n';
+ else
+ *p++ = (i % 64) + '@';
+
+ len = sizeof (buff12k);
+
+ ret = es_write (fp, (void *)&len, sizeof (len), NULL);
+ if (ret)
+ {
+ fprintf (stderr, "es_write (1) failed\n");
+ exit (1);
+ }
+
+ es_fflush (fp);
+
+ o = 0;
+ n = len;
+
+ while (1)
+ {
+ size_t n0, n1;
+
+ n0 = n > 4096 ? 4096 : n;
+ memcpy (buff4k, buff12k + o, n0);
+
+ ret = es_write (fp, buff4k, n0, &n1);
+ if (ret || n0 != n1)
+ {
+ fprintf (stderr, "es_write (2) failed\n");
+ exit (1);
+ }
+
+ o += n0;
+ n -= n0;
+ if (n == 0)
+ break;
+ }
+
+ es_fclose (fp);
+ exit (0);
+}
+
+
+static void
+test_pipe_stream (const char *pgmname)
+{
+ gpg_error_t err;
+ gnupg_process_t proc;
+ estream_t outfp;
+ const char *argv[2];
+ unsigned int len;
+ size_t n;
+ off_t o;
+ int ret;
+
+ argv[0] = "--server";
+ argv[1] = NULL;
+
+ err = gnupg_process_spawn (pgmname, argv,
+ (GNUPG_PROCESS_STDOUT_PIPE
+ |GNUPG_PROCESS_STDERR_KEEP),
+ NULL, NULL, &proc);
+ if (err)
+ {
+ fprintf (stderr, "gnupg_process_spawn failed\n");
+ exit (1);
+ }
+
+ gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
+
+ ret = es_read (outfp, (void *)&len, sizeof (len), NULL);
+ if (ret)
+ {
+ fprintf (stderr, "es_read (1) failed\n");
+ exit (1);
+ }
+
+ o = 0;
+ while (1)
+ {
+ if (es_feof (outfp))
+ break;
+
+ ret = es_read (outfp, buff4k, sizeof (buff4k), &n);
+ if (ret)
+ {
+ fprintf (stderr, "es_read (2) failed\n");
+ exit (1);
+ }
+
+ memcpy (buff12k + o, buff4k, n);
+ o += n;
+ }
+
+ if (o != sizeof (buff12k))
+ {
+ fprintf (stderr, "received data with wrong length %d\n", (int)o);
+ exit (1);
+ }
+ es_fclose (outfp);
+ gnupg_process_release (proc);
+}
int
main (int argc, char **argv)
{
+ const char *myname = "no-pgm";
+
if (argc)
- { argc--; argv++; }
+ {
+ myname = argv[0];
+ argc--; argv++;
+ }
if (argc && !strcmp (argv[0], "--verbose"))
{
verbose = 1;
argc--; argv++;
}
+ if (argc && !strcmp (argv[0], "--server"))
+ run_server ();
+#ifndef HAVE_W32_SYSTEM
test_close_all_fds ();
+#endif
+ test_pipe_stream (myname);
return 0;
}
diff --git a/common/t-iobuf.c b/common/t-iobuf.c
index bdeab99a4..aacf27a8b 100644
--- a/common/t-iobuf.c
+++ b/common/t-iobuf.c
@@ -1,3 +1,36 @@
+/* t-iobuf.c - Simple module test for iobuf.c
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
+ */
+
+/* The whole code here does not very fill into our general test frame
+ * work patter. But let's keep it as it is. */
+
#include <config.h>
#include <stdio.h>
#include <string.h>
@@ -7,6 +40,20 @@
#include "iobuf.h"
#include "stringhelp.h"
+
+static void *
+xmalloc (size_t n)
+{
+ void *p = malloc (n);
+ if (!p)
+ {
+ fprintf (stderr, "t-iobuf: out of core\n");
+ abort ();
+ }
+ return p;
+}
+
+
/* Return every other byte. In particular, reads two bytes, returns
the second one. */
static int
@@ -86,7 +133,7 @@ static struct content_filter_state *
content_filter_new (const char *buffer)
{
struct content_filter_state *state
- = malloc (sizeof (struct content_filter_state));
+ = xmalloc (sizeof (struct content_filter_state));
state->pos = 0;
state->len = strlen (buffer);
@@ -215,8 +262,7 @@ main (int argc, char *argv[])
allocate a buffer that is 5 bytes long, then no reallocation
should be required. */
size = 5;
- buffer = malloc (size);
- assert (buffer);
+ buffer = xmalloc (size);
max_len = 100;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 4);
@@ -229,7 +275,7 @@ main (int argc, char *argv[])
requires 6 bytes of storage. We pass a buffer that is 5 bytes
large and we allow the buffer to be grown. */
size = 5;
- buffer = malloc (size);
+ buffer = xmalloc (size);
max_len = 100;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 5);
@@ -243,7 +289,7 @@ main (int argc, char *argv[])
requires 7 bytes of storage. We pass a buffer that is 5 bytes
large and we don't allow the buffer to be grown. */
size = 5;
- buffer = malloc (size);
+ buffer = xmalloc (size);
max_len = 5;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 4);
diff --git a/common/util.h b/common/util.h
index aa24e39e6..6b948510e 100644
--- a/common/util.h
+++ b/common/util.h
@@ -360,8 +360,6 @@ char *try_make_printable_string (const void *p, size_t n, int delim);
char *make_printable_string (const void *p, size_t n, int delim);
char *decode_c_string (const char *src);
-int is_file_compressed (const byte *buf, unsigned int buflen);
-
int match_multistr (const char *multistr,const char *match);
int gnupg_compare_version (const char *a, const char *b);
diff --git a/configure.ac b/configure.ac
index 953e2616f..fe7e82108 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,8 +28,8 @@ min_automake_version="1.16.3"
# another commit and push so that the git magic is able to work.
m4_define([mym4_package],[gnupg])
m4_define([mym4_major], [2])
-m4_define([mym4_minor], [4])
-m4_define([mym4_micro], [4])
+m4_define([mym4_minor], [5])
+m4_define([mym4_micro], [0])
# To start a new development series, i.e a new major or minor number
# you need to mark an arbitrary commit before the first beta release
@@ -53,7 +53,7 @@ AC_INIT([mym4_package],[mym4_version],[https://bugs.gnupg.org])
# When changing the SWDB tag please also adjust the hard coded tags in
# build-aux/speedo.mk, build-aux/getswdb.sh, and Makefile.am
# As well as the source info for the man pages.
-AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch])
+AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg26", [swdb tag for this branch])
NEED_GPGRT_VERSION=1.46
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index b460ed3b3..799f7cd5f 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -394,6 +394,9 @@ static enum
} tor_mode;
+/* Flag indicating that we are in supervised mode. */
+static int is_supervised;
+
/* Counter for the active connections. */
static int active_connections;
@@ -1330,6 +1333,8 @@ main (int argc, char **argv)
if (!opt.quiet)
log_info(_("WARNING: \"%s\" is a deprecated option\n"), "--supervised");
+ is_supervised = 1;
+
/* In supervised mode, we expect file descriptor 3 to be an
already opened, listening socket.
@@ -2389,7 +2394,7 @@ handle_connections (assuan_fd_t listen_fd)
/* Shutdown test. */
if (shutdown_pending)
{
- if (!active_connections)
+ if (!active_connections || is_supervised)
break; /* ready */
/* Do not accept new connections but keep on running the
diff --git a/dirmngr/ldap-wrapper.c b/dirmngr/ldap-wrapper.c
index 23d514cf9..2ec944c72 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));
+ 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"), 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);
+ 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;
+ 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));
+ 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);
+ 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,
+ 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,
+ 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,22 @@ 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_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_PROC_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 +899,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);
+ 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/call-keyboxd.c b/g10/call-keyboxd.c
index 7f4d5f493..dc3d30a93 100644
--- a/g10/call-keyboxd.c
+++ b/g10/call-keyboxd.c
@@ -94,8 +94,6 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
log_error ("oops: trying to cleanup an active keyboxd context\n");
else
{
- kbx_client_data_release (kbl->kcd);
- kbl->kcd = NULL;
if (kbl->ctx && in_transaction)
{
/* This is our hack to commit the changes done during a
@@ -112,6 +110,15 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
}
assuan_release (kbl->ctx);
kbl->ctx = NULL;
+ /*
+ * Since there may be pipe output FD sent to the server (so
+ * that it can receive data through the pipe), we should
+ * release the assuan connection before releasing KBL->KCD.
+ * This way, the data receiving thread can finish cleanly,
+ * and we can join the thread.
+ */
+ kbx_client_data_release (kbl->kcd);
+ kbl->kcd = NULL;
}
xfree (kbl);
}
@@ -223,7 +230,7 @@ open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl)
return err;
}
- err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 1);
+ err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 0);
if (err)
{
assuan_release (kbl->ctx);
diff --git a/g10/cipher-aead.c b/g10/cipher-aead.c
index 640d8432f..0c07e65de 100644
--- a/g10/cipher-aead.c
+++ b/g10/cipher-aead.c
@@ -174,8 +174,6 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
log_debug ("aead packet: len=%lu extralen=%d\n",
(unsigned long)ed.len, ed.extralen);
- write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d",
- cfx->dek->algo, ed.aead_algo);
print_cipher_algo_note (cfx->dek->algo);
if (build_packet( a, &pkt))
@@ -488,6 +486,11 @@ cipher_filter_aead (void *opaque, int control,
{
mem2str (buf, "cipher_filter_aead", *ret_len);
}
+ else if (control == IOBUFCTRL_INIT)
+ {
+ write_status_printf (STATUS_BEGIN_ENCRYPTION, "0 %d %d",
+ cfx->dek->algo, cfx->dek->use_aead);
+ }
return rc;
}
diff --git a/g10/cipher-cfb.c b/g10/cipher-cfb.c
index 3ba8eb738..29bf2477c 100644
--- a/g10/cipher-cfb.c
+++ b/g10/cipher-cfb.c
@@ -72,9 +72,6 @@ write_header (cipher_filter_context_t *cfx, iobuf_t a)
log_info (_("Hint: Do not use option %s\n"), "--rfc2440");
}
- write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d",
- ed.mdc_method, cfx->dek->algo);
-
init_packet (&pkt);
pkt.pkttype = cfx->dek->use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
pkt.pkt.encrypted = &ed;
@@ -182,6 +179,12 @@ cipher_filter_cfb (void *opaque, int control,
{
mem2str (buf, "cipher_filter_cfb", *ret_len);
}
+ else if (control == IOBUFCTRL_INIT)
+ {
+ write_status_printf (STATUS_BEGIN_ENCRYPTION, "%d %d",
+ cfx->dek->use_mdc ? DIGEST_ALGO_SHA1 : 0,
+ cfx->dek->algo);
+ }
return rc;
}
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 9aeafa292..b335b9797 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -410,8 +410,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
text_filter_context_t tfx;
progress_filter_context_t *pfx;
int do_compress = !!default_compress_algo();
- char peekbuf[32];
- int peekbuflen;
if (!gnupg_rng_is_compliant (opt.compliance))
{
@@ -448,14 +446,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
return rc;
}
- peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf);
- if (peekbuflen < 0)
- {
- peekbuflen = 0;
- if (DBG_FILTER)
- log_debug ("peeking at input failed\n");
- }
-
handle_progress (pfx, inp, filename);
if (opt.textmode)
@@ -517,17 +507,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
/**/ : "CFB");
}
- if (do_compress
- && cfx.dek
- && (cfx.dek->use_mdc || cfx.dek->use_aead)
- && !opt.explicit_compress_option
- && is_file_compressed (peekbuf, peekbuflen))
- {
- if (opt.verbose)
- log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
- do_compress = 0;
- }
-
if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out )))
{
iobuf_cancel (inp);
@@ -598,6 +577,24 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
+ /* Register the cipher filter. */
+ if (mode)
+ iobuf_push_filter (out,
+ cfx.dek->use_aead? cipher_filter_aead
+ /**/ : cipher_filter_cfb,
+ &cfx );
+
+ if (do_compress
+ && cfx.dek
+ && (cfx.dek->use_mdc || cfx.dek->use_aead)
+ && !opt.explicit_compress_option
+ && is_file_compressed (inp))
+ {
+ if (opt.verbose)
+ log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
+ do_compress = 0;
+ }
+
if (!opt.no_literal)
{
/* Note that PT has been initialized above in !no_literal mode. */
@@ -617,13 +614,6 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
pkt.pkt.generic = NULL;
}
- /* Register the cipher filter. */
- if (mode)
- iobuf_push_filter (out,
- cfx.dek->use_aead? cipher_filter_aead
- /**/ : cipher_filter_cfb,
- &cfx );
-
/* Register the compress filter. */
if ( do_compress )
{
@@ -783,7 +773,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
PKT_plaintext *pt = NULL;
DEK *symkey_dek = NULL;
STRING2KEY *symkey_s2k = NULL;
- int rc = 0, rc2 = 0;
+ int rc = 0;
u32 filesize;
cipher_filter_context_t cfx;
armor_filter_context_t *afx = NULL;
@@ -792,8 +782,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
progress_filter_context_t *pfx;
PK_LIST pk_list;
int do_compress;
- char peekbuf[32];
- int peekbuflen;
if (filefd != -1 && filename)
return gpg_error (GPG_ERR_INV_ARG); /* Both given. */
@@ -866,14 +854,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (opt.verbose)
log_info (_("reading from '%s'\n"), iobuf_get_fname_nonnull (inp));
- peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf);
- if (peekbuflen < 0)
- {
- peekbuflen = 0;
- if (DBG_FILTER)
- log_debug ("peeking at input failed\n");
- }
-
handle_progress (pfx, inp, filename);
if (opt.textmode)
@@ -900,25 +880,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (!cfx.dek->use_aead)
cfx.dek->use_mdc = !!use_mdc (pk_list, cfx.dek->algo);
- /* Only do the is-file-already-compressed check if we are using a
- * MDC or AEAD. This forces compressed files to be re-compressed if
- * we do not have a MDC to give some protection against chosen
- * ciphertext attacks. */
- if (do_compress
- && (cfx.dek->use_mdc || cfx.dek->use_aead)
- && !opt.explicit_compress_option
- && is_file_compressed (peekbuf, peekbuflen))
- {
- if (opt.verbose)
- log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
- do_compress = 0;
- }
- if (rc2)
- {
- rc = rc2;
- goto leave;
- }
-
make_session_key (cfx.dek);
if (DBG_CRYPTO)
log_printhex (cfx.dek->key, cfx.dek->keylen, "DEK is: ");
@@ -959,6 +920,26 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
+ /* Register the cipher filter. */
+ iobuf_push_filter (out,
+ cfx.dek->use_aead? cipher_filter_aead
+ /**/ : cipher_filter_cfb,
+ &cfx);
+
+ /* Only do the is-file-already-compressed check if we are using a
+ * MDC or AEAD. This forces compressed files to be re-compressed if
+ * we do not have a MDC to give some protection against chosen
+ * ciphertext attacks. */
+ if (do_compress
+ && (cfx.dek->use_mdc || cfx.dek->use_aead)
+ && !opt.explicit_compress_option
+ && is_file_compressed (inp))
+ {
+ if (opt.verbose)
+ log_info(_("'%s' already compressed\n"), filename? filename: "[stdin]");
+ do_compress = 0;
+ }
+
if (!opt.no_literal)
{
pt->timestamp = make_timestamp();
@@ -973,12 +954,6 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
else
cfx.datalen = filesize && !do_compress ? filesize : 0;
- /* Register the cipher filter. */
- iobuf_push_filter (out,
- cfx.dek->use_aead? cipher_filter_aead
- /**/ : cipher_filter_cfb,
- &cfx);
-
/* Register the compress filter. */
if (do_compress)
{
diff --git a/g10/mainproc.c b/g10/mainproc.c
index ce0fdaaac..7dea49728 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -2542,8 +2542,6 @@ check_sig_and_print (CTX c, kbnode_t node)
release_kbnode( keyblock );
if (rc)
g10_errors_seen = 1;
- if (opt.batch && rc)
- g10_exit (1);
}
else /* Error checking the signature. (neither Good nor Bad). */
{
@@ -2660,7 +2658,8 @@ proc_tree (CTX c, kbnode_t node)
}
for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE));)
- check_sig_and_print (c, n1);
+ if (check_sig_and_print (c, n1) && opt.batch)
+ break;
}
else if (node->pkt->pkttype == PKT_GPG_CONTROL
@@ -2679,8 +2678,8 @@ proc_tree (CTX c, kbnode_t node)
}
for (n1 = node; (n1 = find_next_kbnode (n1, PKT_SIGNATURE));)
- check_sig_and_print (c, n1);
-
+ if (check_sig_and_print (c, n1) && opt.batch)
+ break;
}
else if (node->pkt->pkttype == PKT_SIGNATURE)
{
@@ -2807,7 +2806,8 @@ proc_tree (CTX c, kbnode_t node)
if (multiple_ok)
{
for (n1 = node; n1; (n1 = find_next_kbnode(n1, PKT_SIGNATURE)))
- check_sig_and_print (c, n1);
+ if (check_sig_and_print (c, n1) && opt.batch)
+ break;
}
else
check_sig_and_print (c, node);
diff --git a/g10/photoid.c b/g10/photoid.c
index fc8866121..8cc7e3a20 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -27,9 +27,6 @@
# include <winsock2.h>
# endif
# include <windows.h>
-# ifndef VER_PLATFORM_WIN32_WINDOWS
-# define VER_PLATFORM_WIN32_WINDOWS 1
-# endif
#endif
#include "gpg.h"
@@ -95,8 +92,15 @@ w32_system (const char *command)
return -1;
}
if (DBG_EXTPROG)
- log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n",
- see.hProcess, (int)see.hInstApp);
+ {
+ /* hInstApp has HINSTANCE type. The documentations says
+ that it's not a true HINSTANCE and it can be cast only to
+ an int. */
+ int hinstance = (intptr_t)see.hInstApp;
+
+ log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n",
+ see.hProcess, hinstance);
+ }
if (!see.hProcess)
{
@@ -381,16 +385,7 @@ static const char *
get_default_photo_command(void)
{
#if defined(_WIN32)
- OSVERSIONINFO osvi;
-
- memset(&osvi,0,sizeof(osvi));
- osvi.dwOSVersionInfoSize=sizeof(osvi);
- GetVersionEx(&osvi);
-
- if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
- return "start /w %i";
- else
- return "!ShellExecute 400 %i";
+ return "!ShellExecute 400 %i";
#elif defined(__APPLE__)
/* OS X. This really needs more than just __APPLE__. */
return "open %I";
@@ -600,34 +595,35 @@ 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,
+ 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_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_wait_process (argv[0], pid, 1, NULL);
+ err = gnupg_process_wait (proc, 1);
if (err)
log_error (_("unnatural exit of external program\n"));
+
+ gnupg_process_release (proc);
}
#endif /* !EXEC_TEMPFILE_ONLY */
}
@@ -695,14 +691,11 @@ 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, 0, NULL, NULL, NULL);
if (err)
log_error (_("unnatural exit of external program\n"));
#endif
diff --git a/g10/plaintext.c b/g10/plaintext.c
index 5c21dd7f6..e12c2bf79 100644
--- a/g10/plaintext.c
+++ b/g10/plaintext.c
@@ -137,8 +137,7 @@ get_output_file (const byte *embedded_name, int embedded_namelen,
if (!tmp || !*tmp)
{
xfree (tmp);
- /* FIXME: Below used to be GPG_ERR_CREATE_FILE */
- err = gpg_error (GPG_ERR_GENERAL);
+ err = gpg_error (GPG_ERR_EEXIST);
goto leave;
}
xfree (fname);
diff --git a/g10/sign.c b/g10/sign.c
index f9984f811..d6ab396af 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1034,9 +1034,6 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
int multifile = 0;
u32 duration=0;
pt_extra_hash_data_t extrahash = NULL;
- char peekbuf[32];
- int peekbuflen = 0;
-
pfx = new_progress_context ();
afx = new_armor_context ();
@@ -1095,14 +1092,6 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
goto leave;
}
- peekbuflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof peekbuf, peekbuf);
- if (peekbuflen < 0)
- {
- peekbuflen = 0;
- if (DBG_FILTER)
- log_debug ("peeking at input failed\n");
- }
-
handle_progress (pfx, inp, fname);
}
@@ -1260,7 +1249,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
int compr_algo = opt.compress_algo;
if (!opt.explicit_compress_option
- && is_file_compressed (peekbuf, peekbuflen))
+ && is_file_compressed (inp))
{
if (opt.verbose)
log_info(_("'%s' already compressed\n"), fname? fname: "[stdin]");
diff --git a/g13/be-encfs.c b/g13/be-encfs.c
index 0e2c68bf3..ac6d6d6cd 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,9 @@ 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,
+ NULL, NULL, NULL);
if (err)
log_error ("failed to run '%s': %s\n",
pgmname, gpg_strerror (err));
@@ -218,12 +220,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 +247,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 +259,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_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/kbx/kbx-client-util.c b/kbx/kbx-client-util.c
index f9d06fab8..ca791d4a3 100644
--- a/kbx/kbx-client-util.c
+++ b/kbx/kbx-client-util.c
@@ -53,6 +53,7 @@ struct kbx_client_data_s
/* Condition variable to sync the datastream with the command. */
npth_mutex_t mutex;
npth_cond_t cond;
+ npth_t thd;
/* The data received from the keyboxd and an error code if there was
* a problem (in which case DATA is also set to NULL. This is only
@@ -103,7 +104,6 @@ prepare_data_pipe (kbx_client_data_t kcd)
int rc;
int inpipe[2];
estream_t infp;
- npth_t thread;
npth_attr_t tattr;
kcd->fp = NULL;
@@ -118,10 +118,14 @@ prepare_data_pipe (kbx_client_data_t kcd)
return err; /* That should not happen. */
}
- err = assuan_sendfd (kcd->ctx, INT2FD (inpipe[1]));
+#ifdef HAVE_W32_SYSTEM
+ err = assuan_sendfd (kcd->ctx, INT2FD (_get_osfhandle (inpipe[1])));
+#else
+ err = assuan_sendfd (kcd->ctx, inpipe[1]);
+#endif
if (err)
{
- log_error ("sending sending fd %d to keyboxd: %s <%s>\n",
+ log_error ("sending fd %d to keyboxd: %s <%s>\n",
inpipe[1], gpg_strerror (err), gpg_strsource (err));
es_fclose (infp);
gnupg_close_pipe (inpipe[1]);
@@ -138,6 +142,7 @@ prepare_data_pipe (kbx_client_data_t kcd)
return 0;
}
+ close (inpipe[1]);
kcd->fp = infp;
@@ -150,8 +155,8 @@ prepare_data_pipe (kbx_client_data_t kcd)
kcd->fp = NULL;
return err;
}
- npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
- rc = npth_create (&thread, &tattr, datastream_thread, kcd);
+ npth_attr_setdetachstate (&tattr, NPTH_CREATE_JOINABLE);
+ rc = npth_create (&kcd->thd, &tattr, datastream_thread, kcd);
if (rc)
{
err = gpg_error_from_errno (rc);
@@ -193,13 +198,8 @@ datastream_thread (void *arg)
gnupg_sleep (1);
continue;
}
- if (nread != 4)
- {
- err = gpg_error (GPG_ERR_EIO);
- log_error ("error reading data length from keyboxd: %s\n",
- "short read");
- continue;
- }
+ if (nread < 4)
+ break;
datalen = buf32_to_size_t (lenbuf);
/* log_debug ("keyboxd announced %zu bytes\n", datalen); */
@@ -329,11 +329,14 @@ kbx_client_data_release (kbx_client_data_t kcd)
if (!kcd)
return;
+
+ if (npth_join (kcd->thd, NULL))
+ log_error ("kbx_client_data_release failed on npth_join");
+
fp = kcd->fp;
kcd->fp = NULL;
- es_fclose (fp); /* That close should let the thread run into an error. */
- /* FIXME: Make thread killing explicit. Otherwise we run in a
- * log_fatal due to the destroyed mutex. */
+ es_fclose (fp);
+
npth_cond_destroy (&kcd->cond);
npth_mutex_destroy (&kcd->mutex);
xfree (kcd);
diff --git a/po/ja.po b/po/ja.po
index d9a1dcd71..73d141545 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -226,8 +226,8 @@ msgid ""
"Please enter a passphrase to protect the received secret key%%0A %s%%0A "
"%s%%0Awithin gpg-agent's key storage"
msgstr ""
-"パスフレーズを入力してください。gpg-agentの鍵の保管で受信した秘密鍵%%0A %s"
-"%%0A %s%%0Aを保護します。"
+"パスフレーズを入力してください。gpg-agentの鍵の保管で受信した秘密鍵%%0A "
+"%s%%0A %s%%0Aを保護します。"
#, c-format
msgid "failed to create stream from socket: %s\n"
@@ -755,8 +755,8 @@ msgstr ""
#, c-format
msgid ""
-"Do you really want to delete the key identified by keygrip%%0A %s%%0A %%C"
-"%%0A?"
+"Do you really want to delete the key identified by keygrip%%0A %s%%0A "
+"%%C%%0A?"
msgstr "本当にこの鍵: keygrip%%0A %s%%0A %%C%%0Aを削除しますか?"
msgid "Delete key"
diff --git a/scd/app.c b/scd/app.c
index 3686c0f6c..468fed294 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -2334,6 +2334,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;
@@ -2360,12 +2372,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);
@@ -2382,7 +2391,9 @@ 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,
+ 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/scd/command.c b/scd/command.c
index 0cf66d08c..9ce3889d2 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -2942,10 +2942,10 @@ void
send_client_notifications (card_t card, int removal)
{
struct {
- pid_t pid;
#ifdef HAVE_W32_SYSTEM
HANDLE handle;
#else
+ pid_t pid;
int signo;
#endif
} killed[50];
@@ -2965,10 +2965,10 @@ send_client_notifications (card_t card, int removal)
if (sl->ctrl_backlink && sl->ctrl_backlink->card_ctx == card)
{
- pid_t pid;
#ifdef HAVE_W32_SYSTEM
HANDLE handle;
#else
+ pid_t pid;
int signo;
#endif
@@ -2983,32 +2983,29 @@ send_client_notifications (card_t card, int removal)
if (!sl->event_signal || !sl->assuan_ctx)
continue;
- pid = assuan_get_pid (sl->assuan_ctx);
-
#ifdef HAVE_W32_SYSTEM
handle = sl->event_signal;
for (kidx=0; kidx < killidx; kidx++)
- if (killed[kidx].pid == pid
- && killed[kidx].handle == handle)
+ if (killed[kidx].handle == handle)
break;
if (kidx < killidx)
- log_info ("event %p (%p) already triggered for client %d\n",
- sl->event_signal, handle, (int)pid);
+ log_info ("event %p already triggered for client\n",
+ sl->event_signal);
else
{
- log_info ("triggering event %p (%p) for client %d\n",
- sl->event_signal, handle, (int)pid);
+ log_info ("triggering event %p for client\n",
+ sl->event_signal);
if (!SetEvent (handle))
log_error ("SetEvent(%p) failed: %s\n",
sl->event_signal, w32_strerror (-1));
if (killidx < DIM (killed))
{
- killed[killidx].pid = pid;
killed[killidx].handle = handle;
killidx++;
}
}
#else /*!HAVE_W32_SYSTEM*/
+ pid = assuan_get_pid (sl->assuan_ctx);
signo = sl->event_signal;
if (pid != (pid_t)(-1) && pid && signo > 0)
diff --git a/sm/keydb.c b/sm/keydb.c
index 38737c96a..9b3c7c8ba 100644
--- a/sm/keydb.c
+++ b/sm/keydb.c
@@ -161,10 +161,17 @@ gpgsm_keydb_deinit_session_data (ctrl_t ctrl)
log_error ("oops: trying to cleanup an active keydb context\n");
else
{
- kbx_client_data_release (kbl->kcd);
- kbl->kcd = NULL;
assuan_release (kbl->ctx);
kbl->ctx = NULL;
+ /*
+ * Since there may be pipe output FD sent to the server (so
+ * that it can receive data through the pipe), we should
+ * release the assuan connection before releasing KBL->KCD.
+ * This way, the data receiving thread can finish cleanly,
+ * and we can join the thread.
+ */
+ kbx_client_data_release (kbl->kcd);
+ kbl->kcd = NULL;
}
xfree (kbl);
}
@@ -580,7 +587,7 @@ open_context (ctrl_t ctrl, keydb_local_t *r_kbl)
return err;
}
- err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 1);
+ err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 0);
if (err)
{
assuan_release (kbl->ctx);
diff --git a/tests/gpgscm/ffi.c b/tests/gpgscm/ffi.c
index ce18e0794..cac052138 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"
@@ -644,6 +647,7 @@ static struct foreign_object_vtable es_object_vtable =
es_object_to_string,
};
+#if 0
static pointer
es_wrap (scheme *sc, estream_t stream)
{
@@ -655,6 +659,7 @@ es_wrap (scheme *sc, estream_t stream)
box->closed = 0;
return sc->vptr->mk_foreign_object (sc, &es_object_vtable, box);
}
+#endif
static struct es_object_box *
es_unwrap (scheme *sc, pointer object)
@@ -753,25 +758,166 @@ 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)
+
+
+#define SPAWN_IO_BUFSIZE 4096
+
+#ifdef HAVE_W32_SYSTEM
+struct rfp {
+ HANDLE hd;
+ char *buf;
+ size_t len;
+ off_t off;
+};
+
+static DWORD __attribute__((stdcall))
+read_from_pipe (void *arg)
+{
+ struct rfp *rfp = arg;
+ DWORD bytes_read;
+
+ if (rfp->hd == INVALID_HANDLE_VALUE)
+ goto errout;
+
+ while (1)
+ {
+ if (!ReadFile (rfp->hd, rfp->buf + rfp->off, rfp->len - rfp->off,
+ &bytes_read, NULL))
+ {
+ DWORD ec = GetLastError ();
+
+ if (ec == ERROR_BROKEN_PIPE)
+ {
+ CloseHandle (rfp->hd);
+ rfp->hd = INVALID_HANDLE_VALUE;
+ break;
+ }
+
+ goto errout;
+ }
+
+ if (bytes_read == 0)
+ /* It may occur, when it writes WriteFile with zero-byte on
+ the other end of the pipe. */
+ continue;
+ else
+ {
+ rfp->off += bytes_read;
+ if (rfp->off == rfp->len)
+ {
+ rfp->len += SPAWN_IO_BUFSIZE;
+ rfp->buf = xtryrealloc (rfp->buf, rfp->len);
+ if (rfp->buf == NULL)
+ goto errout;
+ }
+ }
+ }
+
+ return 0;
+
+ errout:
+ if (rfp->hd != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (rfp->hd);
+ rfp->hd = INVALID_HANDLE_VALUE;
+ }
+ xfree (rfp->buf);
+ rfp->buf = NULL;
+ return 1;
+}
+#endif
+
+
+static pointer
+do_process_spawn_io (scheme *sc, pointer args)
{
FFI_PROLOG ();
pointer arguments;
+ char *a_input;
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;
+#ifdef HAVE_W32_SYSTEM
+ HANDLE out_hd, err_hd;
+#else
+ int out_fd, err_fd;
+#endif
+ char *out_string = NULL;
+ char *err_string = NULL;
+ size_t out_len = SPAWN_IO_BUFSIZE;
+ size_t err_len = SPAWN_IO_BUFSIZE;
+ off_t out_off = 0;
+ off_t err_off = 0;
+ int retcode = -1;
+ pointer p0, p1, p2;
FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args);
- FFI_ARG_OR_RETURN (sc, unsigned int, flags, number, args);
+ FFI_ARG_OR_RETURN (sc, char *, a_input, string, 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 +937,245 @@ 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, NULL, NULL);
+
+ err = es_write (infp, a_input, strlen (a_input), NULL);
+ es_fclose (infp);
+ if (err)
+ {
+ gnupg_process_release (proc);
+ xfree (argv);
+ FFI_RETURN_ERR (sc, err);
+ }
+
+#ifdef HAVE_W32_SYSTEM
+ err = gnupg_process_ctl (proc, GNUPG_PROCESS_GET_HANDLES,
+ NULL, &out_hd, &err_hd);
+#else
+ err = gnupg_process_get_fds (proc, 0, NULL, &out_fd, &err_fd);
+#endif
+ if (err)
+ {
+ gnupg_process_release (proc);
+ xfree (argv);
+ FFI_RETURN_ERR (sc, err);
+ }
+
+ out_string = xtrymalloc (out_len);
+ if (out_string == NULL)
+ goto errout;
+
+ err_string = xtrymalloc (err_len);
+ if (err_string == NULL)
+ goto errout;
+
+#ifdef HAVE_W32_SYSTEM
+ {
+ HANDLE h_thread_rfp_err;
+ struct rfp rfp_out;
+ struct rfp rfp_err;
+ DWORD thread_exit_code;
+
+ rfp_err.hd = err_hd;
+ rfp_err.buf = err_string;
+ rfp_err.len = err_len;
+ rfp_err.off = 0;
+ err_hd = INVALID_HANDLE_VALUE;
+ err_string = NULL;
+
+ h_thread_rfp_err = CreateThread (NULL, 0, read_from_pipe, (void *)&rfp_err,
+ 0, NULL);
+ if (h_thread_rfp_err == NULL)
+ {
+ xfree (rfp_err.buf);
+ CloseHandle (rfp_err.hd);
+ goto errout;
+ }
+
+ rfp_out.hd = out_hd;
+ rfp_out.buf = out_string;
+ rfp_out.len = out_len;
+ rfp_out.off = 0;
+ out_hd = INVALID_HANDLE_VALUE;
+ out_string = NULL;
+
+ if (read_from_pipe (&rfp_out))
+ {
+ CloseHandle (h_thread_rfp_err);
+ xfree (rfp_err.buf);
+ goto errout;
+ }
+
+ out_string = rfp_out.buf;
+ out_off = rfp_out.off;
+
+ WaitForSingleObject (h_thread_rfp_err, INFINITE);
+ GetExitCodeThread (h_thread_rfp_err, &thread_exit_code);
+ CloseHandle (h_thread_rfp_err);
+ if (thread_exit_code)
+ goto errout;
+
+ err_string = rfp_err.buf;
+ err_off = rfp_err.off;
+ }
+#else
+ {
+ fd_set read_fdset;
+ ssize_t bytes_read;
+
+ if (out_fd < 0)
+ goto errout;
+
+ if (err_fd < 0)
+ goto errout;
+
+ FD_ZERO (&read_fdset);
+
+ while (1)
+ {
+ int nfd;
+ int ret;
+
+ if (out_fd >= 0)
+ FD_SET (out_fd, &read_fdset);
+
+ if (err_fd >= 0)
+ FD_SET (err_fd, &read_fdset);
+
+ if (out_fd > err_fd)
+ nfd = out_fd;
+ else
+ nfd = err_fd;
+
+ if (nfd == -1)
+ break;
+
+ ret = select (nfd+1, &read_fdset, NULL, NULL, NULL);
+ if (ret < 0)
+ break;
+
+ if (FD_ISSET (out_fd, &read_fdset))
+ {
+ bytes_read = read (out_fd, out_string + out_off,
+ out_len - out_off);
+ if (bytes_read == 0)
+ {
+ close (out_fd);
+ out_fd = -1;
+ }
+ else if (bytes_read < 0)
+ goto errout;
+ else
+ {
+ out_off += bytes_read;
+ if (out_off == out_len)
+ {
+ out_len += SPAWN_IO_BUFSIZE;
+ out_string = xtryrealloc (out_string, out_len);
+ if (out_string == NULL)
+ goto errout;
+ }
+ }
+ }
+
+ if (FD_ISSET (err_fd, &read_fdset))
+ {
+ bytes_read = read (err_fd, err_string + err_off,
+ err_len - err_off);
+ if (bytes_read == 0)
+ {
+ close (err_fd);
+ err_fd = -1;
+ }
+ else if (bytes_read < 0)
+ goto errout;
+ else
+ {
+ err_off += bytes_read;
+ if (err_off == err_len)
+ {
+ err_len += SPAWN_IO_BUFSIZE;
+ err_string = xtryrealloc (err_string, err_len);
+ if (err_string == NULL)
+ goto errout;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ err = gnupg_process_wait (proc, 1);
+ if (!err)
+ err = gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &retcode);
+
+ gnupg_process_release (proc);
xfree (argv);
-#define IMC(A, B) \
- _cons (sc, sc->vptr->mk_integer (sc, (unsigned long) (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)))));
-#undef IMS
-#undef IMC
+
+ p0 = sc->vptr->mk_integer (sc, (unsigned long)retcode);
+ p1 = sc->vptr->mk_counted_string (sc, out_string, out_off);
+ p2 = sc->vptr->mk_counted_string (sc, err_string, err_off);
+
+ xfree (out_string);
+ xfree (err_string);
+
+ FFI_RETURN_POINTER (sc, _cons (sc, p0,
+ _cons (sc, p1,
+ _cons (sc, p2, sc->NIL, 1), 1), 1));
+ errout:
+ xfree (out_string);
+ xfree (err_string);
+#ifdef HAVE_W32_SYSTEM
+ if (out_hd != INVALID_HANDLE_VALUE)
+ CloseHandle (out_hd);
+ if (err_hd != INVALID_HANDLE_VALUE)
+ CloseHandle (err_hd);
+#else
+ if (out_fd >= 0)
+ close (out_fd);
+ if (err_fd >= 0)
+ close (err_fd);
+#endif
+ gnupg_process_release (proc);
+ xfree (argv);
+ FFI_RETURN_ERR (sc, err);
+}
+
+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 +1192,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 +1679,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_io);
+ 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/scheme.c b/tests/gpgscm/scheme.c
index bde39fcd0..003e85037 100644
--- a/tests/gpgscm/scheme.c
+++ b/tests/gpgscm/scheme.c
@@ -169,7 +169,11 @@ type_to_string (enum scheme_types typ)
case T_SINK: return "sink";
case T_FRAME: return "frame";
}
+#ifdef __GNUC__
+ __builtin_unreachable ();
+#else
assert (! "not reached");
+#endif
}
/* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */
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..1e6d7fea0 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,24 +92,16 @@
(define :stdin car)
(define :stdout cadr)
(define :stderr caddr)
-(define :pid cadddr)
(define (call-with-io what in)
- (let ((h (spawn-process 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)))
- (es-fclose (:stdout h))
- (es-fclose (:stderr h))
- (if (> (*verbose*) 2)
- (info "Child" (:pid h) "returned:"
- `((command ,(stringify what))
- (status ,result)
- (stdout ,out)
- (stderr ,err))))
- (list result out err))))
+ (let ((proc-result (process-spawn-io what in)))
+ (if (> (*verbose*) 2)
+ (info "Child #proc returned:"
+ `((command ,(stringify what))
+ (status ,(car proc-result))
+ (stdout ,(cadr proc-result))
+ (stderr ,(caddr proc-result)))))
+ proc-result))
;; Accessor function for the results of 'call-with-io'. ':stdout' and
;; ':stderr' can also be used.
@@ -129,17 +121,6 @@
(throw (:stderr result)))))
;;
-;; estream helpers.
-;;
-
-(define (es-read-all stream)
- (let loop
- ((acc ""))
- (if (es-feof stream)
- acc
- (loop (string-append acc (es-read stream 4096))))))
-
-;;
;; File management.
;;
(define (file-exists? name)
@@ -351,12 +332,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 +344,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 +387,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 +547,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 +566,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 +576,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 +661,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 +670,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 +700,7 @@
;; Has the test been started yet?
(define (started?)
- (number? pid))
+ proc)
(define (open-log-file)
(unless log-file-name
@@ -738,26 +717,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 290ed485d..4002cc185 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,15 @@ 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_STDOUT_KEEP
+ | GNUPG_PROCESS_STDERR_KEEP),
+ 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/gpg-connect-agent.c b/tools/gpg-connect-agent.c
index eb897287c..6be401c4f 100644
--- a/tools/gpg-connect-agent.c
+++ b/tools/gpg-connect-agent.c
@@ -898,8 +898,10 @@ static void
do_sendfd (assuan_context_t ctx, char *line)
{
estream_t fp;
- char *name, *mode, *p;
- int rc, fd;
+ char *name, *p;
+ int rc;
+ char mode[32];
+ es_syshd_t hd;
/* Get file name. */
name = line;
@@ -911,17 +913,25 @@ do_sendfd (assuan_context_t ctx, char *line)
p++;
/* Get mode. */
- mode = p;
- if (!*mode)
- mode = "r";
+ if (!*p)
+ {
+ mode[0] = 'r';
+ mode[1] = 0;
+ p = &mode[1];
+ }
else
{
- for (p=mode; *p && !spacep (p); p++)
- ;
- if (*p)
- *p++ = 0;
+ int i;
+ for (i = 0; *p && !spacep (p); p++)
+ mode[i++] = *p;
+ mode[i] = 0;
+ p = &mode[i];
}
+#ifdef HAVE_W32_SYSTEM
+ strcpy (p, ",sysopen");
+#endif
+
/* Open and send. */
fp = es_fopen (name, mode);
if (!fp)
@@ -930,15 +940,30 @@ do_sendfd (assuan_context_t ctx, char *line)
name, mode, strerror (errno));
return;
}
- fd = es_fileno (fp);
+ es_syshd (fp, &hd);
+
+#ifdef HAVE_W32_SYSTEM
+ if (opt.verbose)
+ log_error ("file '%s' opened in \"%s\" mode, fd=%p\n",
+ name, mode, hd.u.handle);
+#else
if (opt.verbose)
log_error ("file '%s' opened in \"%s\" mode, fd=%d\n",
- name, mode, fd);
+ name, mode, hd.u.fd);
+#endif
- rc = assuan_sendfd (ctx, INT2FD (fd) );
+#ifdef HAVE_W32_SYSTEM
+ rc = assuan_sendfd (ctx, hd.u.handle);
+ if (rc)
+ log_error ("sending descriptor %p failed: %s\n", hd.u.handle,
+ gpg_strerror (rc));
+#else
+ rc = assuan_sendfd (ctx, hd.u.fd);
if (rc)
- log_error ("sending descriptor %d failed: %s\n", fd, gpg_strerror (rc));
+ log_error ("sending descriptor %d failed: %s\n", hd.u.fd,
+ gpg_strerror (rc));
+#endif
es_fclose (fp);
}
@@ -1013,6 +1038,7 @@ do_open (char *line)
#if defined(HAVE_W32_SYSTEM)
{
HANDLE prochandle, handle, newhandle;
+ char numbuf[35];
handle = (void*)_get_osfhandle (fd);
@@ -1035,11 +1061,13 @@ do_open (char *line)
}
CloseHandle (prochandle);
open_fd_table[fd].handle = newhandle;
+
+ snprintf (numbuf, sizeof numbuf, "%p", open_fd_table[fd].handle);
+ set_var (varname, numbuf);
}
if (opt.verbose)
- log_info ("file '%s' opened in \"%s\" mode, fd=%d (libc=%d)\n",
- name, mode, (int)open_fd_table[fd].handle, fd);
- set_int_var (varname, (int)open_fd_table[fd].handle);
+ log_info ("file '%s' opened in \"%s\" mode, fd=%p (libc=%d)\n",
+ name, mode, open_fd_table[fd].handle, fd);
#else /* Unix */
if (opt.verbose)
log_info ("file '%s' opened in \"%s\" mode, fd=%d\n",
@@ -1060,13 +1088,28 @@ do_open (char *line)
static void
do_close (char *line)
{
- int fd = atoi (line);
+ int fd;
#ifdef HAVE_W32_SYSTEM
int i;
+ gpg_error_t err;
+ es_syshd_t syshd;
+
+ err = gnupg_parse_fdstr (line, &syshd);
+ if (err)
+ {
+ log_error ("given fd (system handle) is not valid\n");
+ return;
+ }
+
+ if (syshd.type == ES_SYSHD_FD)
+ {
+ log_error ("given fd is stdin/out/err\n");
+ return;
+ }
for (i=0; i < DIM (open_fd_table); i++)
- if ( open_fd_table[i].inuse && open_fd_table[i].handle == (void*)fd)
+ if (open_fd_table[i].inuse && open_fd_table[i].handle == syshd.u.handle)
break;
if (i < DIM (open_fd_table))
fd = i;
@@ -1075,6 +1118,8 @@ do_close (char *line)
log_error ("given fd (system handle) has not been opened\n");
return;
}
+#else
+ fd = atoi (line);
#endif
if (fd < 0 || fd >= DIM (open_fd_table))
@@ -1105,7 +1150,7 @@ do_showopen (void)
if (open_fd_table[i].inuse)
{
#ifdef HAVE_W32_SYSTEM
- printf ("%-15d (libc=%d)\n", (int)open_fd_table[i].handle, i);
+ printf ("%p (libc=%d)\n", open_fd_table[i].handle, i);
#else
printf ("%-15d\n", i);
#endif
diff --git a/tools/gpgconf-comp.c b/tools/gpgconf-comp.c
index 90f2f53d3..d6aa9d61b 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,13 @@ 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, 0, 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 +777,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 +805,13 @@ 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, 0, 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 +822,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 +850,13 @@ 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, 0, 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 +867,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 +885,13 @@ 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, 0, 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 +901,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 +919,13 @@ 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, 0, 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 +937,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 +985,9 @@ 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, 0, 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 +995,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 +1336,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 +1369,28 @@ 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_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 +1730,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 +1763,17 @@ 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_STDOUT_PIPE,
+ 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 +1932,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 +1952,17 @@ 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_STDOUT_PIPE,
+ 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 +2045,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 6dcdc9f3c..522ce517b 100644
--- a/tools/gpgconf.c
+++ b/tools/gpgconf.c
@@ -1173,17 +1173,17 @@ 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_STDOUT_PIPE,
+ NULL, NULL, &proc);
if (err)
{
log_error ("error spawning %s: %s", pgmname, gpg_strerror (err));
@@ -1191,6 +1191,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 +1212,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 0994322ea..7af5a2ede 100644
--- a/tools/gpgtar-create.c
+++ b/tools/gpgtar-create.c
@@ -1069,7 +1069,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;
unsigned int skipped_open = 0;
memset (scanctrl, 0, sizeof *scanctrl);
@@ -1228,7 +1228,11 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
{
strlist_t arg;
ccparray_t ccp;
+#ifdef HAVE_W32_SYSTEM
+ HANDLE except[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
+#else
int except[2] = { -1, -1 };
+#endif
const char **argv;
/* '--encrypt' may be combined with '--symmetric', but 'encrypt'
@@ -1246,13 +1250,19 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
ccparray_put (&ccp, "--no");
if (opt.require_compliance)
ccparray_put (&ccp, "--require-compliance");
- if (opt.status_fd != -1)
+ if (opt.status_fd)
{
static char tmpbuf[40];
+ es_syshd_t hd;
- snprintf (tmpbuf, sizeof tmpbuf, "--status-fd=%d", opt.status_fd);
+ snprintf (tmpbuf, sizeof tmpbuf, "--status-fd=%s", opt.status_fd);
ccparray_put (&ccp, tmpbuf);
- except[0] = opt.status_fd;
+ es_syshd (opt.status_stream, &hd);
+#ifdef HAVE_W32_SYSTEM
+ except[0] = hd.u.handle;
+#else
+ except[0] = hd.u.fd;
+#endif
}
ccparray_put (&ccp, "--output");
@@ -1286,14 +1296,15 @@ 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_PROCESS_STDOUT_KEEP
+ | GNUPG_PROCESS_STDERR_KEEP),
+ 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 */
@@ -1332,23 +1343,25 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
write_progress (1, global_written_files, global_total_files);
write_progress (0, global_written_data, global_total_data);
- 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;
}
if (skipped_open)
@@ -1361,7 +1374,7 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
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 936d03e3e..87113b054 100644
--- a/tools/gpgtar-extract.c
+++ b/tools/gpgtar-extract.c
@@ -339,7 +339,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;
unsigned long long notextracted;
@@ -384,7 +384,11 @@ gpgtar_extract (const char *filename, int decrypt)
{
strlist_t arg;
ccparray_t ccp;
+#ifdef HAVE_W32_SYSTEM
+ HANDLE except[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
+#else
int except[2] = { -1, -1 };
+#endif
const char **argv;
ccparray_init (&ccp, 0);
@@ -392,13 +396,19 @@ gpgtar_extract (const char *filename, int decrypt)
ccparray_put (&ccp, "--batch");
if (opt.require_compliance)
ccparray_put (&ccp, "--require-compliance");
- if (opt.status_fd != -1)
+ if (opt.status_fd)
{
static char tmpbuf[40];
+ es_syshd_t hd;
- snprintf (tmpbuf, sizeof tmpbuf, "--status-fd=%d", opt.status_fd);
+ snprintf (tmpbuf, sizeof tmpbuf, "--status-fd=%s", opt.status_fd);
ccparray_put (&ccp, tmpbuf);
- except[0] = opt.status_fd;
+ es_syshd (opt.status_stream, &hd);
+#ifdef HAVE_W32_SYSTEM
+ except[0] = hd.u.handle;
+#else
+ except[0] = hd.u.fd;
+#endif
}
if (opt.with_log)
{
@@ -425,14 +435,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 ? 0 : GNUPG_PROCESS_STDIN_KEEP)
+ | 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)
@@ -472,23 +482,25 @@ 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:
diff --git a/tools/gpgtar-list.c b/tools/gpgtar-list.c
index c5bf25825..0c5e474f3 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);
@@ -468,7 +468,11 @@ gpgtar_list (const char *filename, int decrypt)
{
strlist_t arg;
ccparray_t ccp;
+#ifdef HAVE_W32_SYSTEM
+ HANDLE except[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
+#else
int except[2] = { -1, -1 };
+#endif
const char **argv;
ccparray_init (&ccp, 0);
@@ -476,13 +480,19 @@ gpgtar_list (const char *filename, int decrypt)
ccparray_put (&ccp, "--batch");
if (opt.require_compliance)
ccparray_put (&ccp, "--require-compliance");
- if (opt.status_fd != -1)
+ if (opt.status_fd)
{
static char tmpbuf[40];
+ es_syshd_t hd;
- snprintf (tmpbuf, sizeof tmpbuf, "--status-fd=%d", opt.status_fd);
+ snprintf (tmpbuf, sizeof tmpbuf, "--status-fd=%s", opt.status_fd);
ccparray_put (&ccp, tmpbuf);
- except[0] = opt.status_fd;
+ es_syshd (opt.status_stream, &hd);
+#ifdef HAVE_W32_SYSTEM
+ except[0] = hd.u.handle;
+#else
+ except[0] = hd.u.fd;
+#endif
}
ccparray_put (&ccp, "--output");
ccparray_put (&ccp, "-");
@@ -503,14 +513,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 ? 0 : GNUPG_PROCESS_STDIN_KEEP)
+ | 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 +560,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:
diff --git a/tools/gpgtar.c b/tools/gpgtar.c
index ea1e1e751..f93ba2e65 100644
--- a/tools/gpgtar.c
+++ b/tools/gpgtar.c
@@ -127,7 +127,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oBatch, "batch", "@"),
ARGPARSE_s_n (oAnswerYes, "yes", "@"),
ARGPARSE_s_n (oAnswerNo, "no", "@"),
- ARGPARSE_s_i (oStatusFD, "status-fd", "@"),
+ ARGPARSE_s_s (oStatusFD, "status-fd", "@"),
ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"),
ARGPARSE_s_n (oWithLog, "with-log", "@"),
@@ -398,7 +398,7 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts)
case oBatch: opt.batch = 1; break;
case oAnswerYes: opt.answer_yes = 1; break;
case oAnswerNo: opt.answer_no = 1; break;
- case oStatusFD: opt.status_fd = pargs->r.ret_int; break;
+ case oStatusFD: opt.status_fd = pargs->r.ret_str; break;
case oRequireCompliance: opt.require_compliance = 1; break;
case oWithLog: opt.with_log = 1; break;
@@ -480,7 +480,7 @@ main (int argc, char **argv)
log_assert (sizeof (struct ustar_raw_header) == 512);
/* Set default options */
- opt.status_fd = -1;
+ opt.status_fd = NULL;
/* The configuraton directories for use by gpgrt_argparser. */
gpgrt_set_confdir (GPGRT_CONFDIR_SYS, gnupg_sysconfdir ());
@@ -512,31 +512,32 @@ main (int argc, char **argv)
/* Set status stream for our own use of --status-fd. The original
* status fd is passed verbatim to gpg. */
- if (opt.status_fd != -1)
+ if (opt.status_fd)
{
- int fd = translate_sys2libc_fd_int (opt.status_fd, 1);
+ es_syshd_t syshd;
- if (!gnupg_fd_valid (fd))
- log_fatal ("status-fd is invalid: %s\n", strerror (errno));
+ err = gnupg_parse_fdstr (opt.status_fd, &syshd);
+ if (err)
+ log_fatal ("status-fd is invalid: %s\n", gpg_strerror (err));
- if (fd == 1)
+ if (syshd.type == ES_SYSHD_FD && syshd.u.fd == 1)
{
opt.status_stream = es_stdout;
if (!skip_crypto)
log_fatal ("using stdout for the status-fd is not possible\n");
}
- else if (fd == 2)
+ else if (syshd.type == ES_SYSHD_FD && syshd.u.fd == 2)
opt.status_stream = es_stderr;
else
{
- opt.status_stream = es_fdopen (fd, "w");
+ opt.status_stream = es_sysopen (&syshd, "w");
if (opt.status_stream)
es_setvbuf (opt.status_stream, NULL, _IOLBF, 0);
}
if (!opt.status_stream)
{
- log_fatal ("can't open fd %d for status output: %s\n",
- fd, strerror (errno));
+ log_fatal ("can't open fd %s for status output: %s\n",
+ opt.status_fd, strerror (errno));
}
}
diff --git a/tools/gpgtar.h b/tools/gpgtar.h
index d86010476..4e36deaeb 100644
--- a/tools/gpgtar.h
+++ b/tools/gpgtar.h
@@ -45,7 +45,7 @@ struct
int batch;
int answer_yes;
int answer_no;
- int status_fd;
+ const char *status_fd;
estream_t status_stream;
int require_compliance;
int with_log;