Fix changing options with gpgconf.

* src/engine-gpgconf.c (gpgconf_write): Connect a pipe to the child's
stderr, and wait for it to be closed as an indication that gpgconf has
exited.  Also improve error handling.

GnuPG-bug-id: 2881
Signed-off-by: Justus Winter <justus@g10code.com>
This commit is contained in:
Justus Winter 2017-01-12 14:05:15 +01:00
parent 186dcd3494
commit 0e242278df

View File

@ -710,8 +710,11 @@ gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
int buflen = 0; int buflen = 0;
char *argv[7]; char *argv[7];
int argc = 0; int argc = 0;
int rp[2]; int rp[2] = { -1, -1 };
struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} }; int errp[2] = { -1, -1 };
struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */},
{-1, 2 /* STDERR_FILENO */, -1},
{-1, -1} };
int status; int status;
int nwrite; int nwrite;
@ -731,19 +734,31 @@ gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
assert (argc < DIM (argv)); assert (argc < DIM (argv));
if (_gpgme_io_pipe (rp, 0) < 0) if (_gpgme_io_pipe (rp, 0) < 0)
return gpg_error_from_syserror (); {
err = gpg_error_from_syserror ();
goto leave;
}
if (_gpgme_io_pipe (errp, 1) < 0)
{
err = gpg_error_from_syserror ();
goto leave;
}
cfd[0].fd = rp[0]; cfd[0].fd = rp[0];
cfd[1].fd = errp[1];
status = _gpgme_io_spawn (gpgconf->file_name, argv, status = _gpgme_io_spawn (gpgconf->file_name, argv,
IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL); IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
if (status < 0) if (status < 0)
{ {
_gpgme_io_close (rp[0]); err = gpg_error_from_syserror ();
_gpgme_io_close (rp[1]); goto leave;
return gpg_error_from_syserror ();
} }
rp[0] = -1;
errp[1] = -1;
for (;;) for (;;)
{ {
if (buflen == 0) if (buflen == 0)
@ -757,14 +772,29 @@ gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
if (buflen < 0) if (buflen < 0)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
_gpgme_io_close (rp[1]); goto leave;
return err;
} }
else if (buflen == 0) else if (buflen == 0)
{ {
/* All is written. */ /* All is written. */
_gpgme_io_close (rp[1]); _gpgme_io_close (rp[1]);
return 0; rp[1] = -1;
for (;;)
{
do
{
buflen = _gpgme_io_read (errp[0], buf, BUFLEN);
}
while (buflen < 0 && errno == EAGAIN);
if (buflen == 0)
{
err = 0;
goto leave;
}
/* XXX: Do something useful with BUF. */
}
} }
} }
@ -782,12 +812,24 @@ gpgconf_write (void *engine, const char *arg1, char *arg2, gpgme_data_t conf)
} }
else if (nwrite < 0) else if (nwrite < 0)
{ {
_gpgme_io_close (rp[1]); err = gpg_error_from_syserror ();
return gpg_error_from_syserror (); goto leave;
} }
} }
return 0; assert (! "reached");
leave:
if (rp[0] != -1)
_gpgme_io_close (rp[0]);
if (rp[1] != -1)
_gpgme_io_close (rp[1]);
if (errp[0] != -1)
_gpgme_io_close (errp[0]);
if (errp[1] != -1)
_gpgme_io_close (errp[1]);
return err;
} }