1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-02 12:01:32 +01:00

common,agent,gpg,dirmngr,g13,scd,tests,tools: New spawn function.

* common/exechelp-posix.c (do_exec, gnupg_spawn_process): Remove.
(check_syscall_func, pre_syscall, post_syscall) : New.
(do_create_socketpair, posix_open_null, call_spawn_cb): New.
(my_exec, spawn_detached, gnupg_spawn_helper): New.
(gnupg_process_spawn, process_kill, gnupg_process_terminate): New.
(gnupg_process_get_fds, gnupg_process_get_streams): New.
(process_vctl, gnupg_process_ctl): New.
(gnupg_process_wait, gnupg_process_release): New.
(gnupg_process_wait_list): New.
* common/exechelp-w32.c: Add definition of _WIN32_WINNT as 0x600.
(check_syscall_func, pre_syscall, post_syscall): New.
(gnupg_spawn_process): Remove.
(check_windows_version): New.
(spawn_detached, gnupg_spawn_helper, gnupg_process_spawn): New.
(gnupg_process_get_fds, gnupg_process_get_streams): New.
(process_kill, process_vctl, gnupg_process_ctl): New.
(gnupg_process_wait, gnupg_process_terminate): New.
(gnupg_process_release, gnupg_process_wait_list): New.
* common/exechelp.h: Re-write for new API.
* common/exectool.c (gnupg_exec_tool_stream): Follow the change.
* common/asshelp.c (start_new_service): Likewise.
* agent/genkey.c (do_check_passphrase_pattern): Likewise.
* dirmngr/ldap-wrapper.c (struct wrapper_context_s): Use PROC.
(destroy_wrapper): Follow the change of API.
(read_log_data): Follow the change of API, use printable_pid.
(ldap_reaper_thread, ldap_wrapper_release_context): Likewise.
(ldap_wrapper_connection_cleanup, ldap_wrapper): Likewise.
* g10/photoid.c (run_with_pipe): Follow the change of API.
(show_photo): Likewise.
* g13/be-encfs.c (run_umount_helper): Likewise.
(run_encfs_tool): Likewise.
* g13/g13.c: Add including ./common/exechelp.h.
* g13/mount.c: Likewise.
* g13/runner.c: Follow the change of API.
* g13/runner.h: Follow the change of API.
* scd/app.c (setup_env): New.
(report_change): Follow the change of API.
* tests/gpgscm/ffi.c (proc_object_finalize): New.
(proc_object_to_string): New.
(proc_wrap, proc_unwrap): New.
(do_spawn_process): Remove.
(do_process_spawn): New.
(setup_std_fds): New.
(do_spawn_process_fd): Remove.
(do_process_spawn_fd): New.
(do_wait_process): Remove.
(do_process_wait): New.
(do_wait_processes): Remove.
* tests/gpgscm/t-child.scm: Follow the change of API.
* tests/gpgscm/tests.scm: Likewise.
* tests/openpgp/defs.scm: Likewise.
* tests/tpm2dtests/defs.scm: Likewise.
* tools/gpg-card.c: Likewise.
* tools/gpgconf-comp.c: Likewise.
* tools/gpgconf.c: Likewise.
* tools/gpgtar-create.c: Likewise.
* tools/gpgtar-extract.c: Likewise.
* tools/gpgtar-list.c: Likewise.

--

GnuPG-bug-id: 6275
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka 2023-05-11 19:18:21 +09:00
parent 1e41878bf2
commit a035938216
No known key found for this signature in database
GPG Key ID: 640114AF89DE6054
25 changed files with 1936 additions and 1621 deletions

View File

@ -99,7 +99,7 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN); const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
estream_t stream_to_check_pattern = NULL; estream_t stream_to_check_pattern = NULL;
const char *argv[10]; const char *argv[10];
pid_t pid; gnupg_process_t proc;
int result, i; int result, i;
const char *pattern; const char *pattern;
char *patternfname; char *patternfname;
@ -142,11 +142,17 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
argv[i] = NULL; argv[i] = NULL;
log_assert (i < sizeof argv); log_assert (i < sizeof argv);
if (gnupg_spawn_process (pgmname, argv, NULL, 0, if (gnupg_process_spawn (pgmname, argv,
&stream_to_check_pattern, NULL, NULL, &pid)) GNUPG_PROCESS_STDIN_PIPE,
NULL, NULL, &proc))
result = 1; /* Execute error - assume password should no be used. */ result = 1; /* Execute error - assume password should no be used. */
else else
{ {
int status;
gnupg_process_get_streams (proc, 0, &stream_to_check_pattern,
NULL, NULL);
es_set_binary (stream_to_check_pattern); es_set_binary (stream_to_check_pattern);
if (es_fwrite (pw, strlen (pw), 1, stream_to_check_pattern) != 1) if (es_fwrite (pw, strlen (pw), 1, stream_to_check_pattern) != 1)
{ {
@ -157,11 +163,13 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
else else
es_fflush (stream_to_check_pattern); es_fflush (stream_to_check_pattern);
es_fclose (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. */ result = 1; /* Helper returned an error - probably a match. */
else else
result = 0; /* Success; i.e. no match. */ result = 0; /* Success; i.e. no match. */
gnupg_release_process (pid); gnupg_process_release (proc);
} }
xfree (patternfname); xfree (patternfname);

View File

@ -523,16 +523,12 @@ start_new_service (assuan_context_t *r_ctx,
&& assuan_socket_connect (ctx, sockname, 0, connect_flags)) && assuan_socket_connect (ctx, sockname, 0, connect_flags))
{ {
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
err = gnupg_spawn_process_detached (program? program : program_name, err = gnupg_process_spawn (program? program : program_name, argv,
argv, NULL); GNUPG_PROCESS_DETACHED,
NULL, NULL, NULL);
#else /*!W32*/ #else /*!W32*/
pid_t pid; err = gnupg_process_spawn (program? program : program_name, argv,
0, NULL, NULL, NULL);
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);
#endif /*!W32*/ #endif /*!W32*/
if (err) if (err)
log_error ("failed to start %s '%s': %s\n", log_error ("failed to start %s '%s': %s\n",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -73,140 +73,103 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
void gnupg_close_pipe (int fd); void gnupg_close_pipe (int fd);
#define GNUPG_SPAWN_NONBLOCK 16 /* The opaque type for a subprocess. */
#define GNUPG_SPAWN_RUN_ASFW 64 typedef struct gnupg_process *gnupg_process_t;
#define GNUPG_SPAWN_DETACHED 128 #ifdef HAVE_W32_SYSTEM
#define GNUPG_SPAWN_KEEP_STDIN 256 struct spawn_cb_arg;
#define GNUPG_SPAWN_KEEP_STDOUT 512 #ifdef NEED_STRUCT_SPAWN_CB_ARG
#define GNUPG_SPAWN_KEEP_STDERR 1024 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
/* Fork and exec the program PGMNAME. #define GNUPG_PROCESS_DETACHED (1 << 1)
If R_INFP is NULL connect stdin of the new process to /dev/null; if /* Specify how to keep/connect standard fds. */
it is not NULL store the address of a pointer to a new estream #define GNUPG_PROCESS_STDIN_PIPE (1 << 8)
there. If R_OUTFP is NULL connect stdout of the new process to #define GNUPG_PROCESS_STDOUT_PIPE (1 << 9)
/dev/null; if it is not NULL store the address of a pointer to a #define GNUPG_PROCESS_STDERR_PIPE (1 << 10)
new estream there. If R_ERRFP is NULL connect stderr of the new #define GNUPG_PROCESS_STDINOUT_SOCKETPAIR (1 << 11)
process to /dev/null; if it is not NULL store the address of a #define GNUPG_PROCESS_STDIN_KEEP (1 << 12)
pointer to a new estream there. On success the pid of the new #define GNUPG_PROCESS_STDOUT_KEEP (1 << 13)
process is stored at PID. On error -1 is stored at PID and if #define GNUPG_PROCESS_STDERR_KEEP (1 << 14)
R_OUTFP or R_ERRFP are not NULL, NULL is stored there. #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)
The arguments for the process are expected in the NULL terminated #define GNUPG_PROCESS_STREAM_NONBLOCK (1 << 16)
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 /* Spawn helper. */
descriptors, terminated by an entry with the value (-1). These void gnupg_spawn_helper (struct spawn_cb_arg *sca);
file descriptors won't be closed before spawning a new program.
Returns 0 on success or an error code. Calling gnupg_wait_process /* Spawn PGMNAME. */
and gnupg_release_process is required if the function succeeded. 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);
FLAGS is a bit vector: /* 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);
GNUPG_SPAWN_NONBLOCK /* Get STREAMs for subprocess I/O. It is the caller which should care
If set the two output streams are created in non-blocking STREAMs (closing STREAMs). */
mode and the input stream is switched to non-blocking mode. gpg_err_code_t gnupg_process_get_streams (gnupg_process_t process,
This is merely a convenience feature because the caller unsigned int flags,
could do the same with gpgrt_set_nonblock. Does not yet gpgrt_stream_t *r_fp_in,
work for Windows. gpgrt_stream_t *r_fp_out,
gpgrt_stream_t *r_fp_err);
GNUPG_SPAWN_DETACHED enum gnupg_process_requests
If set the process will be started as a background process. {
This flag is only useful under W32 (but not W32CE) systems, /* Portable requests */
so that no new console is created and pops up a console GNUPG_PROCESS_NOP = 0,
window when starting the server. Does not work on W32CE. GNUPG_PROCESS_GET_PROC_ID = 1,
GNUPG_PROCESS_GET_EXIT_ID = 2,
GNUPG_SPAWN_RUN_ASFW /* POSIX only */
On W32 (but not on W32CE) run AllowSetForegroundWindow for GNUPG_PROCESS_GET_PID = 16,
the child. Note that due to unknown problems this actually GNUPG_PROCESS_GET_WSTATUS = 17,
allows SetForegroundWindow for all children of this process. GNUPG_PROCESS_KILL = 18,
GNUPG_SPAWN_KEEP_STDIN /* Windows only */
GNUPG_SPAWN_KEEP_STDOUT GNUPG_PROCESS_GET_P_HANDLE = 32,
GNUPG_SPAWN_KEEP_STDERR GNUPG_PROCESS_GET_HANDLES = 33,
Do not assign /dev/null to a non-required standard file GNUPG_PROCESS_GET_EXIT_CODE = 34,
descriptor. GNUPG_PROCESS_KILL_WITH_EC = 35
};
*/ /* Control of a process. */
gpg_error_t gpg_err_code_t gnupg_process_ctl (gnupg_process_t process,
gnupg_spawn_process (const char *pgmname, const char *argv[], unsigned int request, ...);
int *execpt, unsigned int flags,
estream_t *r_infp,
estream_t *r_outfp,
estream_t *r_errfp,
pid_t *pid);
/* Wait for a single PROCESS. */
gpg_err_code_t gnupg_process_wait (gnupg_process_t process, int hang);
/* Simplified version of gnupg_spawn_process. This function forks and /* Terminate a PROCESS. */
then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout gpg_err_code_t gnupg_process_terminate (gnupg_process_t process);
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);
/* Release PROCESS resources. */
void gnupg_process_release (gnupg_process_t process);
/* If HANG is true, waits for the process identified by PID to exit; /* Wait for a multiple processes. */
if HANG is false, checks whether the process has terminated. gpg_err_code_t gnupg_process_wait_list (gnupg_process_t *process_list,
PGMNAME should be the same as supplied to the spawn function and is int count, int hang);
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[] );
#endif /*GNUPG_COMMON_EXECHELP_H*/ #endif /*GNUPG_COMMON_EXECHELP_H*/

View File

@ -38,10 +38,14 @@
#include <gpg-error.h> #include <gpg-error.h>
#include <assuan.h> #include <assuan.h>
#include "i18n.h" #include "i18n.h"
#include "logging.h" #include "logging.h"
#include "membuf.h" #include "membuf.h"
#include "mischelp.h" #include "mischelp.h"
#ifdef HAVE_W32_SYSTEM
#define NEED_STRUCT_SPAWN_CB_ARG 1
#endif
#include "exechelp.h" #include "exechelp.h"
#include "sysutils.h" #include "sysutils.h"
#include "util.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 /* Run the program PGMNAME with the command line arguments given in
* the NULL terminates array ARGV. If INPUT is not NULL it will be * 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 * 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) void *status_cb_value)
{ {
gpg_error_t err; gpg_error_t err;
pid_t pid = (pid_t) -1; gnupg_process_t proc = NULL;
estream_t infp = NULL; estream_t infp = NULL;
estream_t extrafp = NULL; estream_t extrafp = NULL;
estream_t outfp = NULL, errfp = 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; read_and_log_buffer_t fderrstate;
struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL; struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
int quiet = 0; int quiet = 0;
int dummy_exitcode;
memset (fds, 0, sizeof fds); memset (fds, 0, sizeof fds);
memset (&fderrstate, 0, sizeof fderrstate); memset (&fderrstate, 0, sizeof fderrstate);
@ -411,10 +413,15 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
else else
exceptclose[0] = -1; exceptclose[0] = -1;
err = gnupg_spawn_process (pgmname, argv, err = gnupg_process_spawn (pgmname, argv,
exceptclose, GNUPG_SPAWN_NONBLOCK, ((input
input? &infp : NULL, ? GNUPG_PROCESS_STDIN_PIPE
&outfp, &errfp, &pid); : 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) if (extrapipe[0] != -1)
close (extrapipe[0]); close (extrapipe[0]);
if (argsave) if (argsave)
@ -546,20 +553,25 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
es_fclose (outfp); outfp = NULL; es_fclose (outfp); outfp = NULL;
es_fclose (errfp); errfp = NULL; es_fclose (errfp); errfp = NULL;
err = gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL); err = gnupg_process_wait (proc, 1);
pid = (pid_t)(-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: leave:
if (err && pid != (pid_t) -1) if (err && proc)
gnupg_kill_process (pid); gnupg_process_terminate (proc);
es_fclose (infp); es_fclose (infp);
es_fclose (extrafp); es_fclose (extrafp);
es_fclose (outfp); es_fclose (outfp);
es_fclose (errfp); es_fclose (errfp);
if (pid != (pid_t)(-1)) gnupg_process_release (proc);
gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
gnupg_release_process (pid);
copy_buffer_shred (cpbuf_in); copy_buffer_shred (cpbuf_in);
xfree (cpbuf_in); xfree (cpbuf_in);

View File

@ -87,7 +87,7 @@ struct wrapper_context_s
{ {
struct wrapper_context_s *next; 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 int printable_pid; /* Helper to print diagnostics after the process has
* been cleaned up. */ * been cleaned up. */
estream_t fp; /* Connected with stdout of the ldap wrapper. */ 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 static void
destroy_wrapper (struct wrapper_context_s *ctx) destroy_wrapper (struct wrapper_context_s *ctx)
{ {
if (ctx->pid != (pid_t)(-1)) if (ctx->proc)
{ {
gnupg_kill_process (ctx->pid); gnupg_process_terminate (ctx->proc);
gnupg_release_process (ctx->pid); gnupg_process_release (ctx->proc);
} }
ksba_reader_release (ctx->reader); ksba_reader_release (ctx->reader);
SAFE_CLOSE (ctx->fp); SAFE_CLOSE (ctx->fp);
@ -260,7 +260,7 @@ read_log_data (struct wrapper_context_s *ctx)
if (gpg_err_code (err) == GPG_ERR_EAGAIN) if (gpg_err_code (err) == GPG_ERR_EAGAIN)
return 0; return 0;
log_error (_("error reading log from ldap wrapper %d: %s\n"), 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. */ print_log_line (ctx, NULL); /* Flush. */
SAFE_CLOSE (ctx->log_fp); SAFE_CLOSE (ctx->log_fp);
@ -438,50 +438,44 @@ ldap_reaper_thread (void *dummy)
} }
/* Check whether the process is still running. */ /* Check whether the process is still running. */
if (ctx->pid != (pid_t)(-1)) if (ctx->proc)
{
err = gnupg_process_wait (ctx->proc, 0);
if (!err)
{ {
int status; int status;
err = gnupg_wait_process ("[dirmngr_ldap]", ctx->pid, 0, gnupg_process_ctl (ctx->proc, GNUPG_PROCESS_GET_EXIT_ID,
&status); &status);
if (!err)
{
if (DBG_EXTPROG) if (DBG_EXTPROG)
log_info (_("ldap wrapper %d ready"), (int)ctx->pid); log_info (_("ldap wrapper %d ready"), ctx->printable_pid);
ctx->ready = 1; ctx->ready = 1;
gnupg_release_process (ctx->pid); gnupg_process_release (ctx->proc);
ctx->pid = (pid_t)(-1); ctx->proc = NULL;
any_action = 1; any_action = 1;
}
else if (gpg_err_code (err) == GPG_ERR_GENERAL)
{
if (status == 10) if (status == 10)
log_info (_("ldap wrapper %d ready: timeout\n"), log_info (_("ldap wrapper %d ready: timeout\n"),
(int)ctx->pid); ctx->printable_pid);
else else
log_info (_("ldap wrapper %d ready: exitcode=%d\n"), log_info (_("ldap wrapper %d ready: exitcode=%d\n"),
(int)ctx->pid, status); ctx->printable_pid, status);
ctx->ready = 1;
gnupg_release_process (ctx->pid);
ctx->pid = (pid_t)(-1);
any_action = 1;
} }
else if (gpg_err_code (err) != GPG_ERR_TIMEOUT) else if (gpg_err_code (err) != GPG_ERR_TIMEOUT)
{ {
log_error (_("waiting for ldap wrapper %d failed: %s\n"), 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; any_action = 1;
} }
} }
/* Check whether we should terminate the process. */ /* Check whether we should terminate the process. */
if (ctx->pid != (pid_t)(-1) if (ctx->proc && ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
&& ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
{ {
gnupg_kill_process (ctx->pid); gnupg_process_terminate (ctx->proc);
ctx->stamp = (time_t)(-1); ctx->stamp = (time_t)(-1);
log_info (_("ldap wrapper %d stalled - killing\n"), log_info (_("ldap wrapper %d stalled - killing\n"),
(int)ctx->pid); ctx->printable_pid);
/* We need to close the log stream because the cleanup /* We need to close the log stream because the cleanup
* loop waits for it. */ * loop waits for it. */
SAFE_CLOSE (ctx->log_fp); SAFE_CLOSE (ctx->log_fp);
@ -496,10 +490,10 @@ ldap_reaper_thread (void *dummy)
{ {
log_debug ("ldap worker states:\n"); log_debug ("ldap worker states:\n");
for (ctx = reaper_list; ctx; ctx = ctx->next) 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", " ctrl=%p/%d la=%lu rdy=%d\n",
ctx, ctx,
(int)ctx->pid, (int)ctx->printable_pid, ctx->printable_pid,
ctx->reader, ctx->log_fp, ctx->reader, ctx->log_fp,
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0, ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0,
(unsigned long)ctx->stamp, ctx->ready); (unsigned long)ctx->stamp, ctx->ready);
@ -602,9 +596,9 @@ ldap_wrapper_release_context (ksba_reader_t reader)
if (ctx->reader == reader) if (ctx->reader == reader)
{ {
if (DBG_EXTPROG) 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, " ctrl=%p/%d\n", ctx,
(int)ctx->pid, (int)ctx->printable_pid, ctx->printable_pid,
ctx->reader, ctx->reader,
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0); ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
@ -639,8 +633,8 @@ ldap_wrapper_connection_cleanup (ctrl_t ctrl)
{ {
ctx->ctrl->refcount--; ctx->ctrl->refcount--;
ctx->ctrl = NULL; ctx->ctrl = NULL;
if (ctx->pid != (pid_t)(-1)) if (ctx->proc)
gnupg_kill_process (ctx->pid); gnupg_process_terminate (ctx->proc);
if (ctx->fp_err) if (ctx->fp_err)
log_info ("%s: reading from ldap wrapper %d failed: %s\n", log_info ("%s: reading from ldap wrapper %d failed: %s\n",
__func__, ctx->printable_pid, gpg_strerror (ctx->fp_err)); __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[]) ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
{ {
gpg_error_t err; gpg_error_t err;
pid_t pid; gnupg_process_t process;
struct wrapper_context_s *ctx; struct wrapper_context_s *ctx;
int i; int i;
int j; int j;
@ -854,9 +848,10 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
return err; return err;
} }
err = gnupg_spawn_process (pgmname, arg_list, err = gnupg_process_spawn (pgmname, arg_list,
NULL, GNUPG_SPAWN_NONBLOCK, (GNUPG_PROCESS_STDOUT_PIPE
NULL, &outfp, &errfp, &pid); | GNUPG_PROCESS_STDERR_PIPE),
NULL, NULL, &process);
if (err) if (err)
{ {
xfree (arg_list); xfree (arg_list);
@ -864,9 +859,11 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err)); log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
return 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->proc = process;
ctx->printable_pid = (int) pid;
ctx->fp = outfp; ctx->fp = outfp;
ctx->log_fp = errfp; ctx->log_fp = errfp;
ctx->ctrl = ctrl; ctx->ctrl = ctrl;
@ -902,7 +899,7 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
if (DBG_EXTPROG) if (DBG_EXTPROG)
{ {
log_debug ("ldap wrapper %d started (%p, %s)", 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++) for (i=0; arg_list[i]; i++)
log_printf (" [%s]", arg_list[i]); log_printf (" [%s]", arg_list[i]);
log_printf ("\n"); log_printf ("\n");

View File

@ -594,34 +594,35 @@ run_with_pipe (struct spawn_info *info, const void *image, u32 len)
" external programs\n")); " external programs\n"));
return; return;
#else /* !EXEC_TEMPFILE_ONLY */ #else /* !EXEC_TEMPFILE_ONLY */
int to[2];
pid_t pid;
gpg_error_t err; gpg_error_t err;
const char *argv[4]; const char *argv[4];
gnupg_process_t proc;
err = gnupg_create_pipe (to);
if (err)
return;
fill_command_argv (argv, info->command); fill_command_argv (argv, info->command);
err = gnupg_spawn_process_fd (argv[0], argv+1, to[0], -1, -1, &pid); err = gnupg_process_spawn (argv[0], argv+1, GNUPG_PROCESS_STDIN_PIPE,
NULL, NULL, &proc);
close (to[0]);
if (err) if (err)
{
log_error (_("unable to execute shell '%s': %s\n"), log_error (_("unable to execute shell '%s': %s\n"),
argv[0], gpg_strerror (err)); argv[0], gpg_strerror (err));
close (to[1]);
}
else else
{ {
write (to[1], image, len); int fd_in;
close (to[1]);
err = gnupg_wait_process (argv[0], pid, 1, NULL); err = gnupg_process_get_fds (proc, 0, &fd_in, NULL, NULL);
if (err)
log_error ("unable to get pipe connection '%s': %s\n",
argv[2], gpg_strerror (err));
else
{
write (fd_in, image, len);
close (fd_in);
}
err = gnupg_process_wait (proc, 1);
if (err) if (err)
log_error (_("unnatural exit of external program\n")); log_error (_("unnatural exit of external program\n"));
gnupg_process_release (proc);
} }
#endif /* !EXEC_TEMPFILE_ONLY */ #endif /* !EXEC_TEMPFILE_ONLY */
} }
@ -689,14 +690,11 @@ show_photo (const char *command, const char *name, const void *image, u32 len)
log_error (_("system error while calling external program: %s\n"), log_error (_("system error while calling external program: %s\n"),
strerror (errno)); strerror (errno));
#else #else
pid_t pid;
gpg_error_t err; gpg_error_t err;
const char *argv[4]; const char *argv[4];
fill_command_argv (argv, spawn->command); fill_command_argv (argv, spawn->command);
err = gnupg_spawn_process_fd (argv[0], argv+1, -1, -1, -1, &pid); err = gnupg_process_spawn (argv[0], argv+1, 0, NULL, NULL, NULL);
if (!err)
err = gnupg_wait_process (argv[0], pid, 1, NULL);
if (err) if (err)
log_error (_("unnatural exit of external program\n")); log_error (_("unnatural exit of external program\n"));
#endif #endif

View File

@ -28,10 +28,10 @@
#include "g13.h" #include "g13.h"
#include "../common/i18n.h" #include "../common/i18n.h"
#include "keyblob.h" #include "keyblob.h"
#include "be-encfs.h"
#include "runner.h"
#include "../common/sysutils.h" #include "../common/sysutils.h"
#include "../common/exechelp.h" #include "../common/exechelp.h"
#include "runner.h"
#include "be-encfs.h"
/* Command values used to run the encfs tool. */ /* Command values used to run the encfs tool. */
@ -81,7 +81,9 @@ run_umount_helper (const char *mountpoint)
args[1] = mountpoint; args[1] = mountpoint;
args[2] = NULL; 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) if (err)
log_error ("failed to run '%s': %s\n", log_error ("failed to run '%s': %s\n",
pgmname, gpg_strerror (err)); pgmname, gpg_strerror (err));
@ -218,12 +220,11 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
gpg_error_t err; gpg_error_t err;
encfs_parm_t parm; encfs_parm_t parm;
runner_t runner = NULL; runner_t runner = NULL;
int outbound[2] = { -1, -1 };
int inbound[2] = { -1, -1 };
const char *pgmname; const char *pgmname;
const char *argv[10]; const char *argv[10];
pid_t pid = (pid_t)(-1);
int idx; int idx;
gnupg_process_t proc;
int inbound, outbound;
(void)ctrl; (void)ctrl;
@ -246,15 +247,6 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
if (err) if (err)
goto leave; 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; pgmname = ENCFS;
idx = 0; idx = 0;
argv[idx++] = "-f"; argv[idx++] = "-f";
@ -267,47 +259,42 @@ run_encfs_tool (ctrl_t ctrl, enum encfs_cmds cmd,
argv[idx++] = NULL; argv[idx++] = NULL;
assert (idx <= DIM (argv)); assert (idx <= DIM (argv));
err = gnupg_spawn_process_fd (pgmname, argv, err = gnupg_process_spawn (pgmname, argv,
outbound[0], -1, inbound[1], &pid); (GNUPG_PROCESS_STDIN_PIPE
| GNUPG_PROCESS_STDERR_PIPE),
NULL, NULL, &proc);
if (err) if (err)
{ {
log_error ("error spawning '%s': %s\n", pgmname, gpg_strerror (err)); log_error ("error spawning '%s': %s\n", pgmname, gpg_strerror (err));
goto leave; goto leave;
} }
close (outbound[0]); outbound[0] = -1;
close ( inbound[1]); inbound[1] = -1;
runner_set_fds (runner, inbound[0], outbound[1]); err = gnupg_process_get_fds (proc, 0, &outbound, NULL, &inbound);
inbound[0] = -1; /* Now owned by RUNNER. */ if (err)
outbound[1] = -1; /* Now owned by RUNNER. */ {
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); runner_set_handler (runner, encfs_handler, encfs_handler_cleanup, parm);
parm = NULL; /* Now owned by RUNNER. */ parm = NULL; /* Now owned by RUNNER. */
runner_set_pid (runner, pid); runner_set_proc (runner, proc);
pid = (pid_t)(-1); /* The process is now owned by RUNNER. */
err = runner_spawn (runner); err = runner_spawn (runner);
if (err) if (err)
{
gnupg_process_release (proc);
goto leave; goto leave;
}
*r_id = runner_get_rid (runner); *r_id = runner_get_rid (runner);
log_info ("running '%s' in the background\n", pgmname); log_info ("running '%s' in the background\n", pgmname);
leave: 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); runner_release (runner);
encfs_handler_cleanup (parm); encfs_handler_cleanup (parm);
return err; return err;

View File

@ -40,6 +40,7 @@
#include "../common/gc-opt-flags.h" #include "../common/gc-opt-flags.h"
#include "../common/asshelp.h" #include "../common/asshelp.h"
#include "../common/init.h" #include "../common/init.h"
#include "../common/exechelp.h"
#include "keyblob.h" #include "keyblob.h"
#include "server.h" #include "server.h"
#include "runner.h" #include "runner.h"

View File

@ -34,10 +34,11 @@
#include "backend.h" #include "backend.h"
#include "g13tuple.h" #include "g13tuple.h"
#include "mountinfo.h" #include "mountinfo.h"
#include "runner.h"
#include "../common/host2net.h" #include "../common/host2net.h"
#include "server.h" /*(g13_keyblob_decrypt)*/ #include "server.h" /*(g13_keyblob_decrypt)*/
#include "../common/sysutils.h" #include "../common/sysutils.h"
#include "../common/exechelp.h"
#include "runner.h"
#include "call-syshelp.h" #include "call-syshelp.h"

View File

@ -29,8 +29,8 @@
#include "g13.h" #include "g13.h"
#include "../common/i18n.h" #include "../common/i18n.h"
#include "keyblob.h" #include "keyblob.h"
#include "runner.h"
#include "../common/exechelp.h" #include "../common/exechelp.h"
#include "runner.h"
#include "mountinfo.h" #include "mountinfo.h"
/* The runner object. */ /* The runner object. */
@ -55,7 +55,7 @@ struct runner_s
2 = Thread is running and someone is holding a reference. */ 2 = Thread is running and someone is holding a reference. */
int refcount; 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 in_fd; /* File descriptors to read from the engine. */
int out_fd; /* File descriptors to write to the engine. */ int out_fd; /* File descriptors to write to the engine. */
engine_handler_fnc_t handler; /* The handler functions. */ engine_handler_fnc_t handler; /* The handler functions. */
@ -157,16 +157,16 @@ runner_release (runner_t runner)
if (runner->handler_cleanup) if (runner->handler_cleanup)
runner->handler_cleanup (runner->handler_data); 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. */ /* 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 /* (Actually we should use the program name and not the
arbitrary NAME of the runner object. However it does not arbitrary NAME of the runner object. However it does not
matter because that information is only used for matter because that information is only used for
diagnostics.) */ diagnostics.) */
gnupg_wait_process (runner->name, runner->pid, 1, NULL); gnupg_process_wait (runner->proc, 1);
gnupg_release_process (runner->pid); gnupg_process_release (runner->proc);
} }
xfree (runner->name); xfree (runner->name);
@ -212,7 +212,7 @@ runner_new (runner_t *r_runner, const char *name)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
} }
runner->refcount = 1; runner->refcount = 1;
runner->pid = (pid_t)(-1); runner->proc = NULL;
runner->in_fd = -1; runner->in_fd = -1;
runner->out_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. */ owned by the runner object. */
void 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; return;
runner->pid = pid; runner->proc = proc;
} }
@ -366,15 +366,17 @@ runner_thread (void *arg)
} }
/* Now wait for the process to finish. */ /* Now wait for the process to finish. */
if (!err && runner->pid != (pid_t)(-1)) if (!err && runner->proc)
{ {
int exitcode; int exitcode;
log_debug ("runner thread waiting ...\n"); log_debug ("runner thread waiting ...\n");
err = gnupg_wait_process (runner->name, runner->pid, 1, &exitcode); err = gnupg_process_wait (runner->proc, 1);
gnupg_release_process (runner->pid); if (!err)
runner->pid = (pid_t)(-1); gnupg_process_ctl (runner->proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
if (err) gnupg_process_release (runner->proc);
runner->proc = NULL;
if (exitcode)
log_error ("running '%s' failed (exitcode=%d): %s\n", log_error ("running '%s' failed (exitcode=%d): %s\n",
runner->name, exitcode, gpg_strerror (err)); runner->name, exitcode, gpg_strerror (err));
log_debug ("runner thread waiting finished\n"); 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. */ need to change the thread to wait on an event. */
runner->cancel_flag = 1; runner->cancel_flag = 1;
/* For now we use the brutal way and kill the process. */ /* For now we use the brutal way and kill the process. */
gnupg_kill_process (runner->pid); gnupg_process_terminate (runner->proc);
} }
} }

View File

@ -49,7 +49,7 @@ runner_t runner_find_by_rid (unsigned int rid);
/* Functions to set properties of the runner. */ /* Functions to set properties of the runner. */
void runner_set_fds (runner_t runner, int in_fd, int out_fd); 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. */ /* Register the handler functions with a runner. */
void runner_set_handler (runner_t runner, void runner_set_handler (runner_t runner,

View File

@ -2333,6 +2333,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 static void
report_change (int slot, int old_status, int cur_status) report_change (int slot, int old_status, int cur_status)
{ {
@ -2360,12 +2372,9 @@ report_change (int slot, int old_status, int cur_status)
else else
{ {
gpg_error_t err; gpg_error_t err;
const char *args[9], *envs[2]; const char *args[9];
char numbuf1[30], numbuf2[30], numbuf3[30]; char numbuf1[30], numbuf2[30], numbuf3[30];
envs[0] = envstr;
envs[1] = NULL;
sprintf (numbuf1, "%d", slot); sprintf (numbuf1, "%d", slot);
sprintf (numbuf2, "0x%04X", old_status); sprintf (numbuf2, "0x%04X", old_status);
sprintf (numbuf3, "0x%04X", cur_status); sprintf (numbuf3, "0x%04X", cur_status);
@ -2382,7 +2391,9 @@ report_change (int slot, int old_status, int cur_status)
args[8] = NULL; args[8] = NULL;
fname = make_filename (gnupg_homedir (), "scd-event", 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) if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
log_error ("failed to run event handler '%s': %s\n", log_error ("failed to run event handler '%s': %s\n",
fname, gpg_strerror (err)); fname, gpg_strerror (err));

View File

@ -42,6 +42,9 @@
#endif #endif
#include "../../common/util.h" #include "../../common/util.h"
#ifdef HAVE_W32_SYSTEM
#define NEED_STRUCT_SPAWN_CB_ARG
#endif
#include "../../common/exechelp.h" #include "../../common/exechelp.h"
#include "../../common/sysutils.h" #include "../../common/sysutils.h"
@ -753,25 +756,86 @@ do_es_write (scheme *sc, pointer args)
} }
/* Process handling. */ /* 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 static pointer
do_spawn_process (scheme *sc, pointer args) proc_wrap (scheme *sc, gnupg_process_t proc)
{
struct proc_object_box *box = xmalloc (sizeof *box);
if (box == NULL)
return sc->NIL;
box->proc = proc;
return sc->vptr->mk_foreign_object (sc, &proc_object_vtable, box);
}
static struct proc_object_box *
proc_unwrap (scheme *sc, pointer object)
{
(void) sc;
if (! is_foreign_object (object))
return NULL;
if (sc->vptr->get_foreign_object_vtable (object) != &proc_object_vtable)
return NULL;
return sc->vptr->get_foreign_object_data (object);
}
#define CONVERSION_proc(SC, X) proc_unwrap (SC, X)
#define IS_A_proc(SC, X) proc_unwrap (SC, X)
static pointer
do_process_spawn (scheme *sc, pointer args)
{ {
FFI_PROLOG (); FFI_PROLOG ();
pointer arguments; pointer arguments;
char **argv; char **argv;
size_t len; size_t len;
unsigned int flags; unsigned int flags;
gnupg_process_t proc = NULL;
estream_t infp; estream_t infp;
estream_t outfp; estream_t outfp;
estream_t errfp; estream_t errfp;
pid_t pid;
FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args); FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args);
FFI_ARG_OR_RETURN (sc, unsigned int, flags, number, args); FFI_ARG_OR_RETURN (sc, unsigned int, flags, number, args);
flags |= (GNUPG_PROCESS_STDIN_PIPE
| GNUPG_PROCESS_STDOUT_PIPE
| GNUPG_PROCESS_STDERR_PIPE);
FFI_ARGS_DONE_OR_RETURN (sc, args); FFI_ARGS_DONE_OR_RETURN (sc, args);
err = ffi_list2argv (sc, arguments, &argv, &len); err = ffi_list2argv (sc, arguments, &argv, &len);
@ -791,38 +855,55 @@ do_spawn_process (scheme *sc, pointer args)
fprintf (stderr, "\n"); fprintf (stderr, "\n");
} }
err = gnupg_spawn_process (argv[0], (const char **) &argv[1], err = gnupg_process_spawn (argv[0], (const char **) &argv[1],
NULL, flags, NULL, NULL, &proc);
flags, err = gnupg_process_get_streams (proc, 0, &infp, &outfp, &errfp);
&infp, &outfp, &errfp, &pid);
xfree (argv); xfree (argv);
#define IMC(A, B) \ #define IMP(A, B) \
_cons (sc, sc->vptr->mk_integer (sc, (unsigned long) (A)), (B), 1) _cons (sc, proc_wrap (sc, (A)), (B), 1)
#define IMS(A, B) \ #define IMS(A, B) \
_cons (sc, es_wrap (sc, (A)), (B), 1) _cons (sc, es_wrap (sc, (A)), (B), 1)
FFI_RETURN_POINTER (sc, IMS (infp, FFI_RETURN_POINTER (sc, IMS (infp,
IMS (outfp, IMS (outfp,
IMS (errfp, IMS (errfp,
IMC (pid, sc->NIL))))); IMP (proc, sc->NIL)))));
#undef IMS #undef IMS
#undef IMC #undef IMC
} }
static void
setup_std_fds (struct spawn_cb_arg *sca)
{
int *std_fds = sca->arg;
#ifdef HAVE_W32_SYSTEM
sca->hd[0] = std_fds[0] == -1?
INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle (std_fds[0]);
sca->hd[1] = std_fds[1] == -1?
INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle (std_fds[1]);
sca->hd[2] = std_fds[2] == -1?
INVALID_HANDLE_VALUE : (HANDLE)_get_osfhandle (std_fds[2]);
#else
sca->fds[0] = std_fds[0];
sca->fds[1] = std_fds[1];
sca->fds[2] = std_fds[2];
#endif
}
static pointer static pointer
do_spawn_process_fd (scheme *sc, pointer args) do_process_spawn_fd (scheme *sc, pointer args)
{ {
FFI_PROLOG (); FFI_PROLOG ();
pointer arguments; pointer arguments;
char **argv; char **argv;
size_t len; size_t len;
int infd, outfd, errfd; int std_fds[3];
gnupg_process_t proc = NULL;
pid_t pid;
FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args); FFI_ARG_OR_RETURN (sc, pointer, arguments, list, args);
FFI_ARG_OR_RETURN (sc, int, infd, number, args); FFI_ARG_OR_RETURN (sc, int, std_fds[0], number, args);
FFI_ARG_OR_RETURN (sc, int, outfd, number, args); FFI_ARG_OR_RETURN (sc, int, std_fds[1], number, args);
FFI_ARG_OR_RETURN (sc, int, errfd, number, args); FFI_ARG_OR_RETURN (sc, int, std_fds[2], number, args);
FFI_ARGS_DONE_OR_RETURN (sc, args); FFI_ARGS_DONE_OR_RETURN (sc, args);
err = ffi_list2argv (sc, arguments, &argv, &len); err = ffi_list2argv (sc, arguments, &argv, &len);
@ -839,107 +920,35 @@ do_spawn_process_fd (scheme *sc, pointer args)
fprintf (stderr, "Executing:"); fprintf (stderr, "Executing:");
for (p = argv; *p; p++) for (p = argv; *p; p++)
fprintf (stderr, " '%s'", *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], err = gnupg_process_spawn (argv[0], (const char **) &argv[1],
infd, outfd, errfd, &pid); 0, setup_std_fds, std_fds, &proc);
xfree (argv); xfree (argv);
FFI_RETURN_INT (sc, pid); FFI_RETURN_POINTER (sc, proc_wrap (sc, proc));
} }
static pointer static pointer
do_wait_process (scheme *sc, pointer args) do_process_wait (scheme *sc, pointer args)
{ {
FFI_PROLOG (); FFI_PROLOG ();
const char *name; struct proc_object_box *box;
pid_t pid;
int hang; int hang;
int retcode = -1;
int retcode; FFI_ARG_OR_RETURN (sc, struct proc_object_box *, box, proc, args);
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, int, hang, bool, args); FFI_ARG_OR_RETURN (sc, int, hang, bool, args);
FFI_ARGS_DONE_OR_RETURN (sc, args); FFI_ARGS_DONE_OR_RETURN (sc, args);
err = gnupg_wait_process (name, pid, hang, &retcode); err = gnupg_process_wait (box->proc, hang);
if (err == GPG_ERR_GENERAL) if (!err)
err = 0; /* Let the return code speak for itself. */ err = gnupg_process_ctl (box->proc, GNUPG_PROCESS_GET_EXIT_ID, &retcode);
if (err == GPG_ERR_TIMEOUT)
err = 0;
FFI_RETURN_INT (sc, retcode); 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. */
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);
xfree (names);
xfree (pids);
xfree (retcodes);
FFI_RETURN_POINTER (sc, retcodes_list);
}
static pointer static pointer
do_pipe (scheme *sc, pointer args) do_pipe (scheme *sc, pointer args)
{ {
@ -1398,13 +1407,12 @@ ffi_init (scheme *sc, const char *argv0, const char *scriptname,
ffi_define_function (sc, make_random_string); ffi_define_function (sc, make_random_string);
/* Process management. */ /* 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, pipe);
ffi_define_function (sc, inbound_pipe); ffi_define_function (sc, inbound_pipe);
ffi_define_function (sc, outbound_pipe); ffi_define_function (sc, outbound_pipe);
ffi_define_function (sc, process_spawn);
ffi_define_function (sc, process_spawn_fd);
ffi_define_function (sc, process_wait);
/* estream functions. */ /* estream functions. */
ffi_define_function_name (sc, "es-fclose", es_fclose); ffi_define_function_name (sc, "es-fclose", es_fclose);

View File

@ -69,37 +69,36 @@
(assert (string=? "" (:stderr r)))) (assert (string=? "" (:stderr r))))
(define (spawn what) (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"))) (let ((proc0 (spawn `(,(qualify "t-child") "return0")))
(pid1 (spawn `(,(qualify "t-child") "return0")))) (proc1 (spawn `(,(qualify "t-child") "return0"))))
(assert (equal? '(0 0) (assert (= (process-wait proc0 #t) 0))
(wait-processes '("child0" "child1") (list pid0 pid1) #t)))) (assert (= (process-wait proc1 #t) 0)))
(let ((pid0 (spawn `(,(qualify "t-child") "return1"))) (let ((proc0 (spawn `(,(qualify "t-child") "return1")))
(pid1 (spawn `(,(qualify "t-child") "return0")))) (proc1 (spawn `(,(qualify "t-child") "return0"))))
(assert (equal? '(1 0) (assert (= (process-wait proc0 #t) 1))
(wait-processes '("child0" "child1") (list pid0 pid1) #t)))) (assert (= (process-wait proc1 #t) 0)))
(let ((pid0 (spawn `(,(qualify "t-child") "return0"))) (let ((proc0 (spawn `(,(qualify "t-child") "return0")))
(pid1 (spawn `(,(qualify "t-child") "return77"))) (proc1 (spawn `(,(qualify "t-child") "return77")))
(pid2 (spawn `(,(qualify "t-child") "return1")))) (proc2 (spawn `(,(qualify "t-child") "return1"))))
(assert (equal? '(0 77 1) (assert (= (process-wait proc0 #t) 0))
(wait-processes '("child0" "child1" "child2") (assert (= (process-wait proc1 #t) 77))
(list pid0 pid1 pid2) #t)))) (assert (= (process-wait proc2 #t) 1)))
(let* ((p (pipe)) (let* ((p (pipe))
(pid0 (spawn-process-fd (proc0 (process-spawn-fd
`(,(qualify "t-child") "hello_stdout") `(,(qualify "t-child") "hello_stdout")
CLOSED_FD (:write-end p) STDERR_FILENO)) CLOSED_FD (:write-end p) STDERR_FILENO))
(_ (close (:write-end p))) (_ (close (:write-end p)))
(pid1 (spawn-process-fd (proc1 (process-spawn-fd
`(,(qualify "t-child") "cat") `(,(qualify "t-child") "cat")
(:read-end p) STDOUT_FILENO STDERR_FILENO))) (:read-end p) STDOUT_FILENO STDERR_FILENO)))
(close (:read-end p)) (close (:read-end p))
(assert (assert (= (process-wait proc0 #t) 0))
(equal? '(0 0) (assert (= (process-wait proc1 #t) 0)))
(wait-processes '("child0" "child1") (list pid0 pid1) #t))))
(echo " world.") (echo " world.")
(tr:do (tr:do

View File

@ -81,7 +81,7 @@
;; Process management. ;; Process management.
(define CLOSED_FD -1) (define CLOSED_FD -1)
(define (call-with-fds what infd outfd errfd) (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) (define (call what)
(call-with-fds what (call-with-fds what
CLOSED_FD CLOSED_FD
@ -92,19 +92,19 @@
(define :stdin car) (define :stdin car)
(define :stdout cadr) (define :stdout cadr)
(define :stderr caddr) (define :stderr caddr)
(define :pid cadddr) (define :proc cadddr)
(define (call-with-io what in) (define (call-with-io what in)
(let ((h (spawn-process what 0))) (let ((h (process-spawn what 0)))
(es-write (:stdin h) in) (es-write (:stdin h) in)
(es-fclose (:stdin h)) (es-fclose (:stdin h))
(let* ((out (es-read-all (:stdout h))) (let* ((out (es-read-all (:stdout h)))
(err (es-read-all (:stderr h))) (err (es-read-all (:stderr h)))
(result (wait-process (car what) (:pid h) #t))) (result (process-wait (:proc h) #t)))
(es-fclose (:stdout h)) (es-fclose (:stdout h))
(es-fclose (:stderr h)) (es-fclose (:stderr h))
(if (> (*verbose*) 2) (if (> (*verbose*) 2)
(info "Child" (:pid h) "returned:" (info "Child" (:proc h) "returned:"
`((command ,(stringify what)) `((command ,(stringify what))
(status ,result) (status ,result)
(stdout ,out) (stdout ,out)
@ -351,12 +351,8 @@
(define (dump) (define (dump)
(write (list procs source sink producer)) (write (list procs source sink producer))
(newline)) (newline))
(define (add-proc command pid) (define (add-proc proc)
(new (cons (list command pid) procs) source sink producer)) (new (cons proc procs) source sink producer))
(define (commands)
(map car procs))
(define (pids)
(map cadr procs))
(define (set-source source') (define (set-source source')
(new procs source' sink producer)) (new procs source' sink producer))
(define (set-sink sink') (define (set-sink sink')
@ -367,17 +363,19 @@
(new procs source sink producer')))))) (new procs source sink producer'))))))
(define (process-wait-list procs hang)
(map (lambda (p) (process-wait p hang)) procs))
(define (pipe:do . commands) (define (pipe:do . commands)
(let loop ((M (pipeM::new '() CLOSED_FD CLOSED_FD #f)) (cmds commands)) (let loop ((M (pipeM::new '() CLOSED_FD CLOSED_FD #f)) (cmds commands))
(if (null? cmds) (if (null? cmds)
(begin (begin
(if M::producer (M::producer)) (if M::producer (M::producer))
(if (not (null? M::procs)) (if (not (null? M::procs))
(let* ((retcodes (wait-processes (map stringify (M::commands)) (let* ((retcodes (process-wait-list M::procs #t))
(M::pids) #t)) (results (map (lambda (p r) (cons p r))
(results (map (lambda (p r) (append p (list r)))
M::procs retcodes)) M::procs retcodes))
(failed (filter (lambda (x) (not (= 0 (caddr x)))) (failed (filter (lambda (x) (not (= 0 (cdr x))))
results))) results)))
(if (not (null? failed)) (if (not (null? failed))
(throw failed))))) ; xxx nicer reporting (throw failed))))) ; xxx nicer reporting
@ -408,11 +406,11 @@
(define (pipe:spawn command) (define (pipe:spawn command)
(lambda (M) (lambda (M)
(define (do-spawn M new-source) (define (do-spawn M new-source)
(let ((pid (spawn-process-fd command M::source M::sink (let ((proc (process-spawn-fd command M::source M::sink
(if (> (*verbose*) 0) (if (> (*verbose*) 0)
STDERR_FILENO CLOSED_FD))) STDERR_FILENO CLOSED_FD)))
(M' (M::set-source new-source))) (M' (M::set-source new-source)))
(M'::add-proc command pid))) (M'::add-proc proc)))
(if (= CLOSED_FD M::sink) (if (= CLOSED_FD M::sink)
(let* ((p (pipe)) (let* ((p (pipe))
(M' (do-spawn (M::set-sink (:write-end p)) (:read-end p)))) (M' (do-spawn (M::set-sink (:write-end p)) (:read-end p))))
@ -568,8 +566,8 @@
(assert (= (length enqueued) (- i 1))) (assert (= (length enqueued) (- i 1)))
test))))) test)))))
(define (pid->test pid) (define (proc->test proc)
(let ((t (filter (lambda (x) (= pid x::pid)) procs))) (let ((t (filter (lambda (x) (eq? proc x::proc)) procs)))
(if (null? t) #f (car t)))) (if (null? t) #f (car t))))
(define (wait) (define (wait)
(if (null? enqueued) (if (null? enqueued)
@ -587,7 +585,7 @@
(if (null? unfinished) (if (null? unfinished)
(current-environment) (current-environment)
(let ((names (map (lambda (t) t::name) unfinished)) (let ((names (map (lambda (t) t::name) unfinished))
(pids (map (lambda (t) t::pid) unfinished)) (procs (map (lambda (t) t::proc) unfinished))
(any #f)) (any #f))
(for-each (for-each
(lambda (test retcode) (lambda (test retcode)
@ -597,8 +595,8 @@
(test::report) (test::report)
(sem::release!) (sem::release!)
(set! any #t))) (set! any #t)))
(map pid->test pids) (map proc->test procs)
(wait-processes (map stringify names) pids hang)) (process-wait-list procs hang))
;; If some processes finished, try to start new ones. ;; If some processes finished, try to start new ones.
(let loop () (let loop ()
@ -682,7 +680,7 @@
(define (scm setup variant name path . args) (define (scm setup variant name path . args)
;; Start the process. ;; Start the process.
(define (spawn-scm args' in out err) (define (spawn-scm args' in out err)
(spawn-process-fd `(,*argv0* ,@(verbosity (*verbose*)) (process-spawn-fd `(,*argv0* ,@(verbosity (*verbose*))
,(locate-test (test-name path)) ,(locate-test (test-name path))
,@(if setup (force setup) '()) ,@(if setup (force setup) '())
,@args' ,@args) in out err)) ,@args' ,@args) in out err))
@ -691,12 +689,12 @@
(define (binary setup name path . args) (define (binary setup name path . args)
;; Start the process. ;; Start the process.
(define (spawn-binary args' in out err) (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) ,@(if setup (force setup) '()) ,@args' ,@args)
in out err)) in out err))
(new #f name #f spawn-binary #f #f CLOSED_FD (expect-failure? name))) (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 (package
;; XXX: OO glue. ;; XXX: OO glue.
@ -721,7 +719,7 @@
;; Has the test been started yet? ;; Has the test been started yet?
(define (started?) (define (started?)
(number? pid)) proc)
(define (open-log-file) (define (open-log-file)
(unless log-file-name (unless log-file-name
@ -738,26 +736,26 @@
(letfd ((log (open-log-file))) (letfd ((log (open-log-file)))
(with-working-directory directory (with-working-directory directory
(let* ((p (inbound-pipe)) (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)) (close (:write-end p))
(splice (:read-end p) STDERR_FILENO log) (splice (:read-end p) STDERR_FILENO log)
(close (:read-end p)) (close (:read-end p))
(set! pid pid') (set! proc proc')
(set! retcode (wait-process name pid' #t))))) (set! retcode (process-wait proc' #t)))))
(report) (report)
(current-environment)) (current-environment))
(define (run-sync-quiet . args) (define (run-sync-quiet . args)
(set-start-time!) (set-start-time!)
(with-working-directory directory (with-working-directory directory
(set! pid (spawn args CLOSED_FD CLOSED_FD CLOSED_FD))) (set! proc (spawn args CLOSED_FD CLOSED_FD CLOSED_FD)))
(set! retcode (wait-process name pid #t)) (set! retcode (process-wait proc #t))
(set-end-time!) (set-end-time!)
(current-environment)) (current-environment))
(define (run-async . args) (define (run-async . args)
(set-start-time!) (set-start-time!)
(let ((log (open-log-file))) (let ((log (open-log-file)))
(with-working-directory directory (with-working-directory directory
(set! pid (spawn args CLOSED_FD log log))) (set! proc (spawn args CLOSED_FD log log)))
(set! logfd log)) (set! logfd log))
(current-environment)) (current-environment))
(define (status) (define (status)

View File

@ -268,13 +268,14 @@
(define (gpg-pipe args0 args1 errfd) (define (gpg-pipe args0 args1 errfd)
(lambda (source sink) (lambda (source sink)
(let* ((p (pipe)) (let* ((p (pipe))
(task0 (spawn-process-fd `(,@GPG ,@args0) (task0 (process-spawn-fd `(,@GPG ,@args0)
source (:write-end p) errfd)) source (:write-end p) errfd))
(_ (close (:write-end p))) (_ (close (:write-end p)))
(task1 (spawn-process-fd `(,@GPG ,@args1) (task1 (process-spawn-fd `(,@GPG ,@args1)
(:read-end p) sink errfd))) (:read-end p) sink errfd)))
(close (:read-end p)) (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 "GPG_AGENT_INFO" "" #t)
(setenv "GNUPGHOME" (getcwd) #t) (setenv "GNUPGHOME" (getcwd) #t)

View File

@ -217,13 +217,14 @@
(define (gpg-pipe args0 args1 errfd) (define (gpg-pipe args0 args1 errfd)
(lambda (source sink) (lambda (source sink)
(let* ((p (pipe)) (let* ((p (pipe))
(task0 (spawn-process-fd `(,@GPG ,@args0) (task0 (process-spawn-fd `(,@GPG ,@args0)
source (:write-end p) errfd)) source (:write-end p) errfd))
(_ (close (:write-end p))) (_ (close (:write-end p)))
(task1 (spawn-process-fd `(,@GPG ,@args1) (task1 (process-spawn-fd `(,@GPG ,@args1)
(:read-end p) sink errfd))) (:read-end p) sink errfd)))
(close (:read-end p)) (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 ;; Do we have a software tpm

View File

@ -3641,7 +3641,7 @@ cmd_gpg (card_info_t info, char *argstr, int use_gpgsm)
char **argarray; char **argarray;
ccparray_t ccp; ccparray_t ccp;
const char **argv = NULL; const char **argv = NULL;
pid_t pid; gnupg_process_t proc;
int i; int i;
if (!info) if (!info)
@ -3669,15 +3669,15 @@ cmd_gpg (card_info_t info, char *argstr, int use_gpgsm)
goto leave; goto leave;
} }
err = gnupg_spawn_process (use_gpgsm? opt.gpgsm_program:opt.gpg_program, err = gnupg_process_spawn (use_gpgsm? opt.gpgsm_program:opt.gpg_program,
argv, NULL, (GNUPG_SPAWN_KEEP_STDOUT argv,
|GNUPG_SPAWN_KEEP_STDERR), (GNUPG_PROCESS_STDOUT_KEEP
NULL, NULL, NULL, &pid); | GNUPG_PROCESS_STDERR_KEEP),
NULL, NULL, &proc);
if (!err) if (!err)
{ {
err = gnupg_wait_process (use_gpgsm? opt.gpgsm_program:opt.gpg_program, err = gnupg_process_wait (proc, 1);
pid, 1, NULL); gnupg_process_release (proc);
gnupg_release_process (pid);
} }

View File

@ -744,7 +744,7 @@ gpg_agent_runtime_change (int killflag)
gpg_error_t err = 0; gpg_error_t err = 0;
const char *pgmname; const char *pgmname;
const char *argv[5]; const char *argv[5];
pid_t pid = (pid_t)(-1); gnupg_process_t proc = NULL;
int i = 0; int i = 0;
int cmdidx; int cmdidx;
@ -761,13 +761,13 @@ gpg_agent_runtime_change (int killflag)
log_assert (i < DIM(argv)); log_assert (i < DIM(argv));
if (!err) 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) if (!err)
err = gnupg_wait_process (pgmname, pid, 1, NULL); err = gnupg_process_wait (proc, 1);
if (err) if (err)
gc_error (0, 0, "error running '%s %s': %s", gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err)); 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; gpg_error_t err = 0;
const char *pgmname; const char *pgmname;
const char *argv[9]; const char *argv[9];
pid_t pid = (pid_t)(-1); gnupg_process_t proc = NULL;
int i = 0; int i = 0;
int cmdidx; int cmdidx;
@ -805,13 +805,13 @@ scdaemon_runtime_change (int killflag)
log_assert (i < DIM(argv)); log_assert (i < DIM(argv));
if (!err) 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) if (!err)
err = gnupg_wait_process (pgmname, pid, 1, NULL); err = gnupg_process_wait (proc, 1);
if (err) if (err)
gc_error (0, 0, "error running '%s %s': %s", gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err)); 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; gpg_error_t err = 0;
const char *pgmname; const char *pgmname;
const char *argv[9]; const char *argv[9];
pid_t pid = (pid_t)(-1); gnupg_process_t proc = NULL;
int i = 0; int i = 0;
int cmdidx; int cmdidx;
@ -850,13 +850,13 @@ tpm2daemon_runtime_change (int killflag)
log_assert (i < DIM(argv)); log_assert (i < DIM(argv));
if (!err) 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) if (!err)
err = gnupg_wait_process (pgmname, pid, 1, NULL); err = gnupg_process_wait (proc, 1);
if (err) if (err)
gc_error (0, 0, "error running '%s %s': %s", gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err)); pgmname, argv[cmdidx], gpg_strerror (err));
gnupg_release_process (pid); gnupg_process_release (proc);
} }
#endif #endif
@ -867,7 +867,7 @@ dirmngr_runtime_change (int killflag)
gpg_error_t err = 0; gpg_error_t err = 0;
const char *pgmname; const char *pgmname;
const char *argv[6]; const char *argv[6];
pid_t pid = (pid_t)(-1); gnupg_process_t proc = NULL;
int i = 0; int i = 0;
int cmdidx; int cmdidx;
@ -885,13 +885,13 @@ dirmngr_runtime_change (int killflag)
log_assert (i < DIM(argv)); log_assert (i < DIM(argv));
if (!err) 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) if (!err)
err = gnupg_wait_process (pgmname, pid, 1, NULL); err = gnupg_process_wait (proc, 1);
if (err) if (err)
gc_error (0, 0, "error running '%s %s': %s", gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err)); 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; gpg_error_t err = 0;
const char *pgmname; const char *pgmname;
const char *argv[6]; const char *argv[6];
pid_t pid = (pid_t)(-1); gnupg_process_t proc = NULL;
int i = 0; int i = 0;
int cmdidx; int cmdidx;
@ -919,13 +919,13 @@ keyboxd_runtime_change (int killflag)
log_assert (i < DIM(argv)); log_assert (i < DIM(argv));
if (!err) 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) if (!err)
err = gnupg_wait_process (pgmname, pid, 1, NULL); err = gnupg_process_wait (proc, 1);
if (err) if (err)
gc_error (0, 0, "error running '%s %s': %s", gc_error (0, 0, "error running '%s %s': %s",
pgmname, argv[cmdidx], gpg_strerror (err)); 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 *pgmname;
const char *argv[6]; const char *argv[6];
int i; int i;
pid_t pid; gnupg_process_t proc = NULL;
if (component < 0) if (component < 0)
{ {
@ -985,9 +985,9 @@ gc_component_launch (int component)
argv[i] = NULL; argv[i] = NULL;
log_assert (i < DIM(argv)); 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) if (!err)
err = gnupg_wait_process (pgmname, pid, 1, NULL); err = gnupg_process_wait (proc, 1);
if (err) if (err)
gc_error (0, 0, "error running '%s%s%s': %s", gc_error (0, 0, "error running '%s%s%s': %s",
pgmname, pgmname,
@ -995,7 +995,7 @@ gc_component_launch (int component)
: component == GC_COMPONENT_KEYBOXD? " --keyboxd":"", : component == GC_COMPONENT_KEYBOXD? " --keyboxd":"",
" NOP", " NOP",
gpg_strerror (err)); gpg_strerror (err));
gnupg_release_process (pid); gnupg_process_release (proc);
return err; return err;
} }
@ -1336,8 +1336,7 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
const char *pgmname; const char *pgmname;
const char *argv[6]; const char *argv[6];
int i; int i;
pid_t pid; gnupg_process_t proc;
int exitcode;
estream_t errfp; estream_t errfp;
error_line_t errlines; error_line_t errlines;
@ -1370,22 +1369,28 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
result = 0; result = 0;
errlines = NULL; errlines = NULL;
err = gnupg_spawn_process (pgmname, argv, NULL, 0, err = gnupg_process_spawn (pgmname, argv,
NULL, NULL, &errfp, &pid); GNUPG_PROCESS_STDERR_PIPE,
NULL, NULL, &proc);
if (err) if (err)
result |= 1; /* Program could not be run. */ result |= 1; /* Program could not be run. */
else else
{ {
gnupg_process_get_streams (proc, 0, NULL, NULL, &errfp);
errlines = collect_error_output (errfp, errlines = collect_error_output (errfp,
gc_component[component].name); 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) if (exitcode == -1)
result |= 1; /* Program could not be run or it result |= 1; /* Program could not be run or it
terminated abnormally. */ terminated abnormally. */
else if (exitcode)
result |= 2; /* Program returned an error. */ result |= 2; /* Program returned an error. */
} }
gnupg_release_process (pid); gnupg_process_release (proc);
es_fclose (errfp); es_fclose (errfp);
} }
@ -1725,8 +1730,7 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed)
const char *pgmname; const char *pgmname;
const char *argv[2]; const char *argv[2];
estream_t outfp; estream_t outfp;
int exitcode; gnupg_process_t proc;
pid_t pid;
known_option_t *known_option; known_option_t *known_option;
gc_option_t *option; gc_option_t *option;
char *line = NULL; 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. */ /* First we need to read the option table from the program. */
argv[0] = "--dump-option-table"; argv[0] = "--dump-option-table";
argv[1] = NULL; argv[1] = NULL;
err = gnupg_spawn_process (pgmname, argv, NULL, 0, err = gnupg_process_spawn (pgmname, argv,
NULL, &outfp, NULL, &pid); GNUPG_PROCESS_STDOUT_PIPE,
NULL, NULL, &proc);
if (err) if (err)
{ {
gc_error (1, 0, "could not gather option table from '%s': %s", gc_error (1, 0, "could not gather option table from '%s': %s",
pgmname, gpg_strerror (err)); pgmname, gpg_strerror (err));
} }
gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
read_line_parm.pgmname = pgmname; read_line_parm.pgmname = pgmname;
read_line_parm.fp = outfp; read_line_parm.fp = outfp;
read_line_parm.line = line; 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; line_len = read_line_parm.line_len;
log_assert (opt_table_used + pseudo_count == opt_info_used); 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); gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
if (err) if (exitcode)
gc_error (1, 0, "running %s failed (exitcode=%d): %s", gc_error (1, 0, "running %s failed (exitcode=%d): %s",
pgmname, exitcode, gpg_strerror (err)); pgmname, exitcode, gpg_strerror (err));
gnupg_release_process (pid); }
gnupg_process_release (proc);
/* Make the gpgrt option table and the internal option table available. */ /* Make the gpgrt option table and the internal option table available. */
gc_component[component].opt_table = opt_table; 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. */ /* Now read the default options. */
argv[0] = "--gpgconf-list"; argv[0] = "--gpgconf-list";
argv[1] = NULL; argv[1] = NULL;
err = gnupg_spawn_process (pgmname, argv, NULL, 0, err = gnupg_process_spawn (pgmname, argv,
NULL, &outfp, NULL, &pid); GNUPG_PROCESS_STDOUT_PIPE,
NULL, NULL, &proc);
if (err) if (err)
{ {
gc_error (1, 0, "could not gather active options from '%s': %s", gc_error (1, 0, "could not gather active options from '%s': %s",
pgmname, gpg_strerror (err)); pgmname, gpg_strerror (err));
} }
gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0) while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
{ {
char *linep; char *linep;
@ -2030,11 +2045,17 @@ retrieve_options_from_program (gc_component_id_t component, int only_installed)
if (es_fclose (outfp)) if (es_fclose (outfp))
gc_error (1, errno, "error closing %s", pgmname); gc_error (1, errno, "error closing %s", pgmname);
err = gnupg_wait_process (pgmname, pid, 1, &exitcode); err = gnupg_process_wait (proc, 1);
if (err) 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", gc_error (1, 0, "running %s failed (exitcode=%d): %s",
pgmname, exitcode, gpg_strerror (err)); pgmname, exitcode, gpg_strerror (err));
gnupg_release_process (pid); }
gnupg_process_release (proc);
/* At this point, we can parse the configuration file. */ /* At this point, we can parse the configuration file. */

View File

@ -1173,17 +1173,17 @@ show_versions_via_dirmngr (estream_t fp)
const char *pgmname; const char *pgmname;
const char *argv[2]; const char *argv[2];
estream_t outfp; estream_t outfp;
pid_t pid; gnupg_process_t proc;
char *line = NULL; char *line = NULL;
size_t line_len = 0; size_t line_len = 0;
ssize_t length; ssize_t length;
int exitcode;
pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR); pgmname = gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR);
argv[0] = "--gpgconf-versions"; argv[0] = "--gpgconf-versions";
argv[1] = NULL; argv[1] = NULL;
err = gnupg_spawn_process (pgmname, argv, NULL, 0, err = gnupg_process_spawn (pgmname, argv,
NULL, &outfp, NULL, &pid); GNUPG_PROCESS_STDOUT_PIPE,
NULL, NULL, &proc);
if (err) if (err)
{ {
log_error ("error spawning %s: %s", pgmname, gpg_strerror (err)); log_error ("error spawning %s: %s", pgmname, gpg_strerror (err));
@ -1191,6 +1191,7 @@ show_versions_via_dirmngr (estream_t fp)
return; return;
} }
gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0) while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
{ {
/* Strip newline and carriage return, if present. */ /* Strip newline and carriage return, if present. */
@ -1211,14 +1212,17 @@ show_versions_via_dirmngr (estream_t fp)
pgmname, gpg_strerror (err)); pgmname, gpg_strerror (err));
} }
err = gnupg_wait_process (pgmname, pid, 1, &exitcode); err = gnupg_process_wait (proc, 1);
if (err) if (!err)
{ {
int exitcode;
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
log_error ("running %s failed (exitcode=%d): %s\n", log_error ("running %s failed (exitcode=%d): %s\n",
pgmname, exitcode, gpg_strerror (err)); pgmname, exitcode, gpg_strerror (err));
es_fprintf (fp, "[error: can't get further info]\n"); es_fprintf (fp, "[error: can't get further info]\n");
} }
gnupg_release_process (pid); gnupg_process_release (proc);
xfree (line); xfree (line);
} }

View File

@ -1069,7 +1069,7 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
estream_t files_from_stream = NULL; estream_t files_from_stream = NULL;
estream_t outstream = NULL; estream_t outstream = NULL;
int eof_seen = 0; int eof_seen = 0;
pid_t pid = (pid_t)(-1); gnupg_process_t proc = NULL;
unsigned int skipped_open = 0; unsigned int skipped_open = 0;
memset (scanctrl, 0, sizeof *scanctrl); memset (scanctrl, 0, sizeof *scanctrl);
@ -1284,14 +1284,15 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
goto leave; goto leave;
} }
err = gnupg_spawn_process (opt.gpg_program, argv, err = gnupg_process_spawn (opt.gpg_program, argv,
except[0] == -1? NULL : except, (GNUPG_PROCESS_STDIN_PIPE
(GNUPG_SPAWN_KEEP_STDOUT | GNUPG_PROCESS_STDOUT_KEEP
| GNUPG_SPAWN_KEEP_STDERR), | GNUPG_PROCESS_STDERR_KEEP),
&outstream, NULL, NULL, &pid); gnupg_spawn_helper, except, &proc);
xfree (argv); xfree (argv);
if (err) if (err)
goto leave; goto leave;
gnupg_process_get_streams (proc, 0, &outstream, NULL, NULL);
es_set_binary (outstream); es_set_binary (outstream);
} }
else if (opt.outfile) /* No crypto */ else if (opt.outfile) /* No crypto */
@ -1330,23 +1331,25 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
write_progress (1, global_written_files, global_total_files); write_progress (1, global_written_files, global_total_files);
write_progress (0, global_written_data, global_total_data); write_progress (0, global_written_data, global_total_data);
if (pid != (pid_t)(-1)) if (proc)
{ {
int exitcode;
err = es_fclose (outstream); err = es_fclose (outstream);
outstream = NULL; outstream = NULL;
if (err) if (err)
log_error ("error closing pipe: %s\n", gpg_strerror (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); int exitcode;
if (err)
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
if (exitcode)
log_error ("running %s failed (exitcode=%d): %s", log_error ("running %s failed (exitcode=%d): %s",
opt.gpg_program, exitcode, gpg_strerror (err)); opt.gpg_program, exitcode, gpg_strerror (err));
gnupg_release_process (pid);
pid = (pid_t)(-1);
} }
gnupg_process_release (proc);
proc = NULL;
} }
if (skipped_open) if (skipped_open)
@ -1359,7 +1362,7 @@ gpgtar_create (char **inpattern, const char *files_from, int null_names,
if (!err) if (!err)
{ {
gpg_error_t first_err; gpg_error_t first_err;
if (outstream != es_stdout || pid != (pid_t)(-1)) if (outstream != es_stdout)
first_err = es_fclose (outstream); first_err = es_fclose (outstream);
else else
first_err = es_fflush (outstream); first_err = es_fflush (outstream);

View File

@ -339,7 +339,7 @@ gpgtar_extract (const char *filename, int decrypt)
char *dirname = NULL; char *dirname = NULL;
struct tarinfo_s tarinfo_buffer; struct tarinfo_s tarinfo_buffer;
tarinfo_t tarinfo = &tarinfo_buffer; tarinfo_t tarinfo = &tarinfo_buffer;
pid_t pid = (pid_t)(-1); gnupg_process_t proc;
char *logfilename = NULL; char *logfilename = NULL;
unsigned long long notextracted; unsigned long long notextracted;
@ -425,14 +425,14 @@ gpgtar_extract (const char *filename, int decrypt)
goto leave; goto leave;
} }
err = gnupg_spawn_process (opt.gpg_program, argv, err = gnupg_process_spawn (opt.gpg_program, argv,
except[0] == -1? NULL : except, ((filename ? 0 : GNUPG_PROCESS_STDIN_KEEP)
((filename? 0 : GNUPG_SPAWN_KEEP_STDIN) | GNUPG_PROCESS_STDOUT_PIPE),
| GNUPG_SPAWN_KEEP_STDERR), gnupg_spawn_helper, except, &proc);
NULL, &stream, NULL, &pid);
xfree (argv); xfree (argv);
if (err) if (err)
goto leave; goto leave;
gnupg_process_get_streams (proc, 0, NULL, &stream, NULL);
es_set_binary (stream); es_set_binary (stream);
} }
else if (filename) else if (filename)
@ -472,23 +472,25 @@ gpgtar_extract (const char *filename, int decrypt)
header = NULL; header = NULL;
} }
if (pid != (pid_t)(-1)) if (proc)
{ {
int exitcode;
err = es_fclose (stream); err = es_fclose (stream);
stream = NULL; stream = NULL;
if (err) if (err)
log_error ("error closing pipe: %s\n", gpg_strerror (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); int exitcode;
if (err)
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
if (exitcode)
log_error ("running %s failed (exitcode=%d): %s", log_error ("running %s failed (exitcode=%d): %s",
opt.gpg_program, exitcode, gpg_strerror (err)); opt.gpg_program, exitcode, gpg_strerror (err));
gnupg_release_process (pid);
pid = (pid_t)(-1);
} }
gnupg_process_release (proc);
proc = NULL;
} }
leave: leave:

View File

@ -460,7 +460,7 @@ gpgtar_list (const char *filename, int decrypt)
strlist_t extheader = NULL; strlist_t extheader = NULL;
struct tarinfo_s tarinfo_buffer; struct tarinfo_s tarinfo_buffer;
tarinfo_t tarinfo = &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); memset (&tarinfo_buffer, 0, sizeof tarinfo_buffer);
@ -503,14 +503,14 @@ gpgtar_list (const char *filename, int decrypt)
goto leave; goto leave;
} }
err = gnupg_spawn_process (opt.gpg_program, argv, err = gnupg_process_spawn (opt.gpg_program, argv,
except[0] == -1? NULL : except, ((filename ? 0 : GNUPG_PROCESS_STDIN_KEEP)
((filename? 0 : GNUPG_SPAWN_KEEP_STDIN) | GNUPG_PROCESS_STDOUT_PIPE),
| GNUPG_SPAWN_KEEP_STDERR), gnupg_spawn_helper, except, &proc);
NULL, &stream, NULL, &pid);
xfree (argv); xfree (argv);
if (err) if (err)
goto leave; goto leave;
gnupg_process_get_streams (proc, 0, NULL, &stream, NULL);
es_set_binary (stream); es_set_binary (stream);
} }
else if (filename) /* No decryption requested. */ else if (filename) /* No decryption requested. */
@ -550,23 +550,24 @@ gpgtar_list (const char *filename, int decrypt)
header = NULL; header = NULL;
} }
if (pid != (pid_t)(-1)) if (proc)
{ {
int exitcode;
err = es_fclose (stream); err = es_fclose (stream);
stream = NULL; stream = NULL;
if (err) if (err)
log_error ("error closing pipe: %s\n", gpg_strerror (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); int exitcode;
if (err)
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &exitcode);
log_error ("running %s failed (exitcode=%d): %s", log_error ("running %s failed (exitcode=%d): %s",
opt.gpg_program, exitcode, gpg_strerror (err)); opt.gpg_program, exitcode, gpg_strerror (err));
gnupg_release_process (pid);
pid = (pid_t)(-1);
} }
gnupg_process_release (proc);
proc = NULL;
} }
leave: leave: