mirror of
git://git.gnupg.org/gnupg.git
synced 2024-11-10 21:38:50 +01:00
common: Allow a second input stream for gnupg_exec_tool_stream.
* common/exechelp-posix.c (do_exec): Add arg 'except' and pass to close_all_fds. (gnupg_spawn_process): Add arg 'except'. Change callers to pass NULL for it. * common/exechelp-w32.c (gnupg_spawn_process): Add dummy arg 'except'. * common/exechelp-w32ce.c (gnupg_spawn_process): Ditto. * common/exectool.c (copy_buffer_do_copy): Allow NULL for SINK. (gnupg_exec_tool_stream): Add arg 'inextra'. Change callers to pass NULL for it. Allow NULL for OUTPUT. -- This hack is a first step to allow calling gpg for verification of signatures. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
e6d9a2d07e
commit
44a32455c8
@ -278,7 +278,7 @@ get_all_open_fds (void)
|
||||
static void
|
||||
do_exec (const char *pgmname, const char *argv[],
|
||||
int fd_in, int fd_out, int fd_err,
|
||||
void (*preexec)(void) )
|
||||
int *except, void (*preexec)(void) )
|
||||
{
|
||||
char **arg_list;
|
||||
int i, j;
|
||||
@ -324,7 +324,7 @@ do_exec (const char *pgmname, const char *argv[],
|
||||
}
|
||||
|
||||
/* Close all other files. */
|
||||
close_all_fds (3, NULL);
|
||||
close_all_fds (3, except);
|
||||
|
||||
if (preexec)
|
||||
preexec ();
|
||||
@ -420,7 +420,7 @@ gnupg_create_pipe (int filedes[2])
|
||||
/* Fork and exec the PGMNAME, see exechelp.h for details. */
|
||||
gpg_error_t
|
||||
gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
void (*preexec)(void), unsigned int flags,
|
||||
int *except, void (*preexec)(void), unsigned int flags,
|
||||
estream_t *r_infp,
|
||||
estream_t *r_outfp,
|
||||
estream_t *r_errfp,
|
||||
@ -525,7 +525,8 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
gcry_control (GCRYCTL_TERM_SECMEM);
|
||||
es_fclose (outfp);
|
||||
es_fclose (errfp);
|
||||
do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1], preexec);
|
||||
do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1],
|
||||
except, preexec);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
@ -575,7 +576,7 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
|
||||
{
|
||||
gcry_control (GCRYCTL_TERM_SECMEM);
|
||||
/* Run child. */
|
||||
do_exec (pgmname, argv, infd, outfd, errfd, NULL);
|
||||
do_exec (pgmname, argv, infd, outfd, errfd, NULL, NULL);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
@ -728,7 +729,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
|
||||
for (i=0; envp[i]; i++)
|
||||
putenv (xstrdup (envp[i]));
|
||||
|
||||
do_exec (pgmname, argv, -1, -1, -1, NULL);
|
||||
do_exec (pgmname, argv, -1, -1, -1, NULL, NULL);
|
||||
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
@ -357,7 +357,7 @@ gnupg_create_pipe (int filedes[2])
|
||||
/* Fork and exec the PGMNAME, see exechelp.h for details. */
|
||||
gpg_error_t
|
||||
gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
void (*preexec)(void), unsigned int flags,
|
||||
int *except, void (*preexec)(void), unsigned int flags,
|
||||
estream_t *r_infp,
|
||||
estream_t *r_outfp,
|
||||
estream_t *r_errfp,
|
||||
@ -388,6 +388,8 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
es_syshd_t syshd;
|
||||
gpg_err_source_t errsource = default_errsource;
|
||||
|
||||
(void)except; /* Not yet used. */
|
||||
|
||||
if (r_infp)
|
||||
*r_infp = NULL;
|
||||
if (r_outfp)
|
||||
|
@ -515,7 +515,7 @@ create_process (const char *pgmname, const char *cmdline,
|
||||
/* Fork and exec the PGMNAME, see exechelp.h for details. */
|
||||
gpg_error_t
|
||||
gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
void (*preexec)(void), unsigned int flags,
|
||||
int *except, void (*preexec)(void), unsigned int flags,
|
||||
estream_t *r_infp,
|
||||
estream_t *r_outfp,
|
||||
estream_t *r_errfp,
|
||||
@ -541,6 +541,7 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
estream_t errfp = NULL;
|
||||
gpg_err_source_t errsource = default_errsource;
|
||||
|
||||
(void)except; /* Not yet used. */
|
||||
(void)preexec;
|
||||
(void)flags;
|
||||
|
||||
|
@ -90,6 +90,10 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
|
||||
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.
|
||||
|
||||
@ -116,7 +120,7 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
|
||||
*/
|
||||
gpg_error_t
|
||||
gnupg_spawn_process (const char *pgmname, const char *argv[],
|
||||
void (*preexec)(void), unsigned int flags,
|
||||
int *execpt, void (*preexec)(void), unsigned int flags,
|
||||
estream_t *r_infp,
|
||||
estream_t *r_outfp,
|
||||
estream_t *r_errfp,
|
||||
|
@ -188,7 +188,8 @@ copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
|
||||
if (c->nread == 0)
|
||||
return 0; /* Done copying. */
|
||||
|
||||
err = es_write (sink, c->writep, c->nread, &nwritten);
|
||||
|
||||
err = sink? es_write (sink, c->writep, c->nread, &nwritten) : 0;
|
||||
if (err)
|
||||
{
|
||||
if (errno == EAGAIN)
|
||||
@ -202,7 +203,7 @@ copy_buffer_do_copy (struct copy_buffer *c, estream_t source, estream_t sink)
|
||||
c->nread -= nwritten;
|
||||
assert (c->writep - c->buffer <= sizeof c->buffer);
|
||||
|
||||
if (es_fflush (sink) && errno != EAGAIN)
|
||||
if (sink && es_fflush (sink) && errno != EAGAIN)
|
||||
err = my_error_from_syserror ();
|
||||
|
||||
return err;
|
||||
@ -228,36 +229,80 @@ 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
|
||||
the process' stdout is written to OUTPUT. On error a diagnostic is
|
||||
printed, and an error code returned. */
|
||||
* 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
|
||||
* the process' stdout is written to OUTPUT. If OUTPUT is NULL the
|
||||
* output is discarded. If INEXTRA is given, an additional input
|
||||
* stream will be passed to the child; to tell the child about this
|
||||
* ARGV is scanned and the first occurrence of an argument
|
||||
* "-&@INEXTRA@" is replaced by the concatenation of "-&" and the
|
||||
* child's file descriptor of the pipe created for the INEXTRA stream.
|
||||
*
|
||||
* On error a diagnostic is printed and an error code returned. */
|
||||
gpg_error_t
|
||||
gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
estream_t input,
|
||||
estream_t input, estream_t inextra,
|
||||
estream_t output)
|
||||
{
|
||||
gpg_error_t err;
|
||||
pid_t pid;
|
||||
estream_t infp = NULL;
|
||||
estream_t extrafp = NULL;
|
||||
estream_t outfp, errfp;
|
||||
es_poll_t fds[3];
|
||||
es_poll_t fds[4];
|
||||
int exceptclose[2];
|
||||
int extrapipe[2] = {-1, -1};
|
||||
char extrafdbuf[20];
|
||||
const char *argsave = NULL;
|
||||
int argsaveidx;
|
||||
int count;
|
||||
read_and_log_buffer_t fderrstate;
|
||||
struct copy_buffer cpbuf[2];
|
||||
struct copy_buffer cpbuf_in, cpbuf_out, cpbuf_extra; /* Fixme: malloc them. */
|
||||
|
||||
memset (fds, 0, sizeof fds);
|
||||
memset (&fderrstate, 0, sizeof fderrstate);
|
||||
copy_buffer_init (&cpbuf[0]);
|
||||
copy_buffer_init (&cpbuf[1]);
|
||||
copy_buffer_init (&cpbuf_in);
|
||||
copy_buffer_init (&cpbuf_out);
|
||||
copy_buffer_init (&cpbuf_extra);
|
||||
|
||||
if (inextra)
|
||||
{
|
||||
err = gnupg_create_outbound_pipe (extrapipe, &extrafp, 1);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error running outbound pipe for extra fp: %s\n",
|
||||
gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
exceptclose[0] = extrapipe[0]; /* Do not close in child. */
|
||||
exceptclose[1] = -1;
|
||||
/* Now find the argument marker and replace by the pipe's fd.
|
||||
Yeah, that is an ugly non-thread safe hack but it safes us to
|
||||
create a copy of the array. */
|
||||
snprintf (extrafdbuf, sizeof extrafdbuf, "-&%d", extrapipe[0]);
|
||||
for (argsaveidx=0; argv[argsaveidx]; argsaveidx++)
|
||||
if (!strcmp (argv[argsaveidx], "-&@INEXTRA@"))
|
||||
{
|
||||
argsave = argv[argsaveidx];
|
||||
argv[argsaveidx] = extrafdbuf;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
exceptclose[0] = -1;
|
||||
|
||||
err = gnupg_spawn_process (pgmname, argv,
|
||||
NULL, GNUPG_SPAWN_NONBLOCK,
|
||||
exceptclose, NULL, GNUPG_SPAWN_NONBLOCK,
|
||||
input? &infp : NULL,
|
||||
&outfp, &errfp, &pid);
|
||||
if (extrapipe[0] != -1)
|
||||
close (extrapipe[0]);
|
||||
if (argsave)
|
||||
argv[argsaveidx] = argsave;
|
||||
if (err)
|
||||
{
|
||||
log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
|
||||
es_fclose (extrafp);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -271,6 +316,11 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
fds[1].want_read = 1;
|
||||
fds[2].stream = errfp;
|
||||
fds[2].want_read = 1;
|
||||
fds[3].stream = extrafp;
|
||||
fds[3].want_write = 1;
|
||||
if (!inextra)
|
||||
fds[3].ignore = 1;
|
||||
|
||||
/* Now read as long as we have something to poll. We continue
|
||||
reading even after EOF or error on stdout so that we get the
|
||||
other error messages or remaining outut. */
|
||||
@ -291,7 +341,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
|
||||
if (fds[0].got_write)
|
||||
{
|
||||
err = copy_buffer_do_copy (&cpbuf[0], input, fds[0].stream);
|
||||
err = copy_buffer_do_copy (&cpbuf_in, input, fds[0].stream);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error feeding data to '%s': %s\n",
|
||||
@ -301,7 +351,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
|
||||
if (es_feof (input))
|
||||
{
|
||||
err = copy_buffer_flush (&cpbuf[0], fds[0].stream);
|
||||
err = copy_buffer_flush (&cpbuf_in, fds[0].stream);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error feeding data to '%s': %s\n",
|
||||
@ -314,9 +364,35 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[3].got_write)
|
||||
{
|
||||
log_assert (inextra);
|
||||
err = copy_buffer_do_copy (&cpbuf_extra, inextra, fds[3].stream);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error feeding data to '%s': %s\n",
|
||||
pgmname, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (es_feof (inextra))
|
||||
{
|
||||
err = copy_buffer_flush (&cpbuf_extra, fds[3].stream);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error feeding data to '%s': %s\n",
|
||||
pgmname, gpg_strerror (err));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
fds[3].ignore = 1; /* ready. */
|
||||
es_fclose (extrafp); extrafp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (fds[1].got_read)
|
||||
{
|
||||
err = copy_buffer_do_copy (&cpbuf[1], fds[1].stream, output);
|
||||
err = copy_buffer_do_copy (&cpbuf_out, fds[1].stream, output);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error reading data from '%s': %s\n",
|
||||
@ -329,7 +405,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
read_and_log_stderr (&fderrstate, fds + 2);
|
||||
}
|
||||
|
||||
err = copy_buffer_flush (&cpbuf[1], output);
|
||||
err = copy_buffer_flush (&cpbuf_out, output);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error reading data from '%s': %s\n",
|
||||
@ -339,6 +415,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
|
||||
read_and_log_stderr (&fderrstate, NULL); /* Flush. */
|
||||
es_fclose (infp); infp = NULL;
|
||||
es_fclose (extrafp); extrafp = NULL;
|
||||
es_fclose (outfp); outfp = NULL;
|
||||
es_fclose (errfp); errfp = NULL;
|
||||
|
||||
@ -350,14 +427,17 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
gnupg_kill_process (pid);
|
||||
|
||||
es_fclose (infp);
|
||||
es_fclose (extrafp);
|
||||
es_fclose (outfp);
|
||||
es_fclose (errfp);
|
||||
if (pid != (pid_t)(-1))
|
||||
gnupg_wait_process (pgmname, pid, 1, NULL);
|
||||
gnupg_release_process (pid);
|
||||
|
||||
copy_buffer_shred (&cpbuf[0]);
|
||||
copy_buffer_shred (&cpbuf[1]);
|
||||
copy_buffer_shred (&cpbuf_in);
|
||||
copy_buffer_shred (&cpbuf_out);
|
||||
if (inextra)
|
||||
copy_buffer_shred (&cpbuf_extra);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -408,7 +488,7 @@ gnupg_exec_tool (const char *pgmname, const char *argv[],
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = gnupg_exec_tool_stream (pgmname, argv, input, output);
|
||||
err = gnupg_exec_tool_stream (pgmname, argv, input, NULL, output);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
|
@ -48,9 +48,9 @@ gpg_error_t gnupg_exec_tool (const char *pgmname, const char *argv[],
|
||||
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
|
||||
the process' stdout is written to OUTPUT. On error a diagnostic is
|
||||
printed, and an error code returned. */
|
||||
printed, and an error code returned. INEXTRA is reserved. */
|
||||
gpg_error_t gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
|
||||
estream_t input,
|
||||
estream_t input, estream_t inextra,
|
||||
estream_t output);
|
||||
|
||||
#endif /* GNUPG_COMMON_EXECTOOL_H */
|
||||
|
@ -1626,7 +1626,7 @@ 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,
|
||||
err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
|
||||
NULL, NULL, &errfp, &pid);
|
||||
if (err)
|
||||
result |= 1; /* Program could not be run. */
|
||||
@ -1965,7 +1965,7 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
|
||||
argv[0] = "--gpgconf-list";
|
||||
argv[1] = NULL;
|
||||
|
||||
err = gnupg_spawn_process (pgmname, argv, NULL, 0,
|
||||
err = gnupg_spawn_process (pgmname, argv, NULL, NULL, 0,
|
||||
NULL, &outfp, NULL, &pid);
|
||||
if (err)
|
||||
{
|
||||
|
@ -932,7 +932,7 @@ gpgtar_create (char **inpattern, int encrypt, int sign)
|
||||
}
|
||||
|
||||
err = gnupg_exec_tool_stream (opt.gpg_program, argv,
|
||||
outstream, cipher_stream);
|
||||
outstream, NULL, cipher_stream);
|
||||
xfree (argv);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
@ -327,7 +327,7 @@ gpgtar_extract (const char *filename, int decrypt)
|
||||
}
|
||||
|
||||
err = gnupg_exec_tool_stream (opt.gpg_program, argv,
|
||||
cipher_stream, stream);
|
||||
cipher_stream, NULL, stream);
|
||||
xfree (argv);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
@ -327,7 +327,7 @@ gpgtar_list (const char *filename, int decrypt)
|
||||
}
|
||||
|
||||
err = gnupg_exec_tool_stream (opt.gpg_program, argv,
|
||||
cipher_stream, stream);
|
||||
cipher_stream, NULL, stream);
|
||||
xfree (argv);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
Loading…
Reference in New Issue
Block a user