1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

Reworked the posix and w32 exechelpers.

This commit is contained in:
Werner Koch 2010-08-20 12:18:38 +00:00
parent be9c4748d0
commit 15330f36a7
13 changed files with 831 additions and 229 deletions

View File

@ -1,3 +1,7 @@
2010-08-19 Werner Koch <wk@g10code.com>
* configure.ac (AH_BOTTOM): Define GPG_ERR_ENABLE_ERRNO_MACROS.
2010-08-09 Werner Koch <wk@g10code.com> 2010-08-09 Werner Koch <wk@g10code.com>
* configure.ac (inet_pton): Check for it. * configure.ac (inet_pton): Check for it.

2
NEWS
View File

@ -35,6 +35,8 @@ Noteworthy changes in version 2.1.x (under development)
* Given sufficient permissions Dirmngr is started automagically. * Given sufficient permissions Dirmngr is started automagically.
* Fixed output of "gpgconf --check-options".
Noteworthy changes in version 2.0.13 (2009-09-04) Noteworthy changes in version 2.0.13 (2009-09-04)
------------------------------------------------- -------------------------------------------------

2
README
View File

@ -16,7 +16,7 @@ INTRODUCTION
GnuPG is GNU's tool for secure communication and data storage. It can GnuPG is GNU's tool for secure communication and data storage. It can
be used to encrypt data and to create digital signatures. It includes be used to encrypt data and to create digital signatures. It includes
an advanced key management facility and is compliant with the proposed an advanced key management facility and is compliant with the proposed
OpenPGP Internet standard as described in RFC2440 and the S/MIME OpenPGP Internet standard as described in RFC4880 and the S/MIME
standard as described by several RFCs. standard as described by several RFCs.
GnuPG is distributed under the terms of the GNU General Public GnuPG is distributed under the terms of the GNU General Public

View File

@ -1,3 +1,31 @@
2010-08-20 Werner Koch <wk@g10code.com>
* exechelp-w32.c (create_inheritable_pipe): Change arg to HANDLE.
* estream.h (es_sysopen_t): New.
* estream.c (es_func_w32_create, es_func_w32_read)
(es_func_w32_write, es_func_w32_seek, es_func_w32_destroy)
(estream_functions_w32, estream_cookie_fd): New. Only for W32.
(es_sysopen, es_sysopen_nc): New.
(do_w32open, do_sysopen): New.
(es_syshd, es_syshd_unlocked): New.
(struct estream_internal): Replace filed FD by SYSHD.
(es_initialize): Clear SYSHD_VALID.
(map_w32_to_errno): New.
(es_get_fd): Remove.
(es_fileno_unlocked): Re-implement using es_syshd.
(es_initialize, es_create): Replace arg FD by SYSHD.
(es_fopen, es_mopen, es_fopenmem, do_fdopen, do_fpopen)
(es_tmpfile): Use SYSHD instead of FD.
(es_destroy): Rename to do_close.
2010-08-19 Werner Koch <wk@g10code.com>
* exechelp-posix.c (create_pipe_and_estream): New.
(gnupg_spawn_process): Rework this function and its calling
convention; it is not used anyway.
* exechelp-w32.c (gnupg_spawn_process): Ditto.
2010-08-18 Werner Koch <wk@g10code.com> 2010-08-18 Werner Koch <wk@g10code.com>
* logging.c (writen): Add arg IS_SOCKET. * logging.c (writen): Add arg IS_SOCKET.

View File

@ -126,9 +126,9 @@ int _setmode (int handle, int mode);
#endif #endif
#ifdef HAVE_W32_SYSTEM #ifdef HAVE_W32_SYSTEM
# define IS_INVALID_FD(a) ((void*)(a) == (void*)(-1)) # define IS_INVALID_FD(a) ((void*)(a) == (void*)(-1)) /* ?? FIXME. */
#else #else
# define IS_INVALID_FD(a) ((a) == -1) # define IS_INVALID_FD(a) ((a) == -1)
#endif #endif
@ -197,6 +197,7 @@ dummy_mutex_call_int (estream_mutex_t mutex)
# define ESTREAM_SYS_YIELD() do { } while (0) # define ESTREAM_SYS_YIELD() do { } while (0)
#endif #endif
/* Misc definitions. */ /* Misc definitions. */
#define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR) #define ES_DEFAULT_OPEN_MODE (S_IRUSR | S_IWUSR)
@ -218,7 +219,7 @@ struct estream_internal
es_cookie_seek_function_t func_seek; es_cookie_seek_function_t func_seek;
es_cookie_close_function_t func_close; es_cookie_close_function_t func_close;
int strategy; int strategy;
int fd; /* Value to return by es_fileno(). */ es_syshd_t syshd; /* A copy of the sytem handle. */
struct struct
{ {
unsigned int err: 1; unsigned int err: 1;
@ -317,7 +318,39 @@ mem_free (void *p)
free (p); free (p);
} }
#ifdef HAVE_W32_SYSTEM
static int
map_w32_to_errno (DWORD w32_err)
{
switch (w32_err)
{
case 0:
return 0;
case ERROR_FILE_NOT_FOUND:
return ENOENT;
case ERROR_PATH_NOT_FOUND:
return ENOENT;
case ERROR_ACCESS_DENIED:
return EPERM;
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_BLOCK:
return EINVAL;
case ERROR_NOT_ENOUGH_MEMORY:
return ENOMEM;
case ERROR_NO_DATA:
return EPIPE;
default:
return EIO;
}
}
#endif /*HAVE_W32_SYSTEM*/
/* /*
* List manipulation. * List manipulation.
@ -744,7 +777,7 @@ static es_cookie_io_functions_t estream_functions_mem =
/* Implementation of fd I/O. */ /* Implementation of file descriptor based I/O. */
/* Cookie for fd objects. */ /* Cookie for fd objects. */
typedef struct estream_cookie_fd typedef struct estream_cookie_fd
@ -886,6 +919,217 @@ static es_cookie_io_functions_t estream_functions_fd =
#ifdef HAVE_W32_SYSTEM
/* Implementation of W32 handle based I/O. */
/* Cookie for fd objects. */
typedef struct estream_cookie_w32
{
HANDLE hd; /* The handle we are using for actual output. */
int no_close; /* If set we won't close the handle. */
} *estream_cookie_w32_t;
/* Create function for w32 handle objects. */
static int
es_func_w32_create (void **cookie, HANDLE hd,
unsigned int modeflags, int no_close)
{
estream_cookie_w32_t w32_cookie;
int err;
w32_cookie = mem_alloc (sizeof (*w32_cookie));
if (!w32_cookie)
err = -1;
else
{
/* CR/LF translations are not supported when using the bare W32
API. If that is really required we need to implemented that
in the upper layer. */
(void)modeflags;
w32_cookie->hd = hd;
w32_cookie->no_close = no_close;
*cookie = w32_cookie;
err = 0;
}
return err;
}
/* Read function for W32 handle objects. */
static ssize_t
es_func_w32_read (void *cookie, void *buffer, size_t size)
{
estream_cookie_w32_t w32_cookie = cookie;
ssize_t bytes_read;
if (w32_cookie->hd == INVALID_HANDLE_VALUE)
{
ESTREAM_SYS_YIELD ();
bytes_read = 0;
}
else
{
do
{
#ifdef HAVE_PTH
/* Note: Our pth_read actually uses HANDLE! */
bytes_read = pth_read ((int)w32_cookie->hd, buffer, size);
#else
DWORD nread, ec;
if (!ReadFile (w32_cookie->hd, buffer, size, &nread, NULL))
{
ec = GetLastError ();
if (ec == ERROR_BROKEN_PIPE)
bytes_read = 0; /* Like our pth_read we handle this as EOF. */
else
{
_set_errno (map_w32_to_errno (ec));
log_debug ("estream: ReadFile returned %d\n",
(int)GetLastError ());
bytes_read = -1;
}
}
else
bytes_read = (int)nread;
#endif
}
while (bytes_read == -1 && errno == EINTR);
}
return bytes_read;
}
/* Write function for W32 handle objects. */
static ssize_t
es_func_w32_write (void *cookie, const void *buffer, size_t size)
{
estream_cookie_w32_t w32_cookie = cookie;
ssize_t bytes_written;
if (w32_cookie->hd == INVALID_HANDLE_VALUE)
{
ESTREAM_SYS_YIELD ();
bytes_written = size; /* Yeah: Success writing to the bit bucket. */
}
else
{
do
{
#ifdef HAVE_PTH
/* Note: Our pth_write actually uses HANDLE! */
bytes_written = pth_write ((int)w32_cookie->hd, buffer, size);
#else
DWORD nwritten;
if (!WriteFile (w32_cookie->hd, buffer, size, &nwritten, NULL))
{
_set_errno (map_w32_to_errno (GetLastError ()));
bytes_written = -1;
}
else
bytes_written = (int)nwritten;
#endif
}
while (bytes_written == -1 && errno == EINTR);
}
return bytes_written;
}
/* Seek function for W32 handle objects. */
static int
es_func_w32_seek (void *cookie, off_t *offset, int whence)
{
estream_cookie_w32_t w32_cookie = cookie;
DWORD method;
LARGE_INTEGER distance, newoff;
if (w32_cookie->hd == INVALID_HANDLE_VALUE)
{
_set_errno (ESPIPE);
return -1;
}
if (whence == SEEK_SET)
{
method = FILE_BEGIN;
distance.QuadPart = (unsigned long long)(*offset);
}
else if (whence == SEEK_CUR)
{
method = FILE_CURRENT;
distance.QuadPart = (long long)(*offset);
}
else if (whence == SEEK_END)
{
method = FILE_END;
distance.QuadPart = (long long)(*offset);
}
else
{
_set_errno (EINVAL);
return -1;
}
#ifdef HAVE_W32CE_SYSTEM
# warning need to use SetFilePointer
#else
if (!SetFilePointerEx (w32_cookie->hd, distance, &newoff, method))
{
_set_errno (map_w32_to_errno (GetLastError ()));
return -1;
}
#endif
*offset = (unsigned long long)newoff.QuadPart;
return 0;
}
/* Destroy function for W32 handle objects. */
static int
es_func_w32_destroy (void *cookie)
{
estream_cookie_w32_t w32_cookie = cookie;
int err;
if (w32_cookie)
{
if (w32_cookie->hd == INVALID_HANDLE_VALUE)
err = 0;
else if (w32_cookie->no_close)
err = 0;
else
{
if (!CloseHandle (w32_cookie->hd))
{
_set_errno (map_w32_to_errno (GetLastError ()));
err = -1;
}
else
err = 0;
}
mem_free (w32_cookie);
}
else
err = 0;
return err;
}
static es_cookie_io_functions_t estream_functions_w32 =
{
es_func_w32_read,
es_func_w32_write,
es_func_w32_seek,
es_func_w32_destroy
};
#endif /*HAVE_W32_SYSTEM*/
/* Implementation of FILE* I/O. */ /* Implementation of FILE* I/O. */
@ -1049,7 +1293,7 @@ static es_cookie_io_functions_t estream_functions_fp =
/* Implementation of file I/O. */ /* Implementation of file I/O. */
/* Create function for file objects. */ /* Create function for fd objects. */
static int static int
es_func_file_create (void **cookie, int *filedes, es_func_file_create (void **cookie, int *filedes,
const char *path, unsigned int modeflags) const char *path, unsigned int modeflags)
@ -1269,7 +1513,8 @@ es_empty (estream_t stream)
/* Initialize STREAM. */ /* Initialize STREAM. */
static void static void
es_initialize (estream_t stream, es_initialize (estream_t stream,
void *cookie, int fd, es_cookie_io_functions_t functions, void *cookie, es_syshd_t *syshd,
es_cookie_io_functions_t functions,
unsigned int modeflags) unsigned int modeflags)
{ {
stream->intern->cookie = cookie; stream->intern->cookie = cookie;
@ -1280,7 +1525,7 @@ es_initialize (estream_t stream,
stream->intern->func_seek = functions.func_seek; stream->intern->func_seek = functions.func_seek;
stream->intern->func_close = functions.func_close; stream->intern->func_close = functions.func_close;
stream->intern->strategy = _IOFBF; stream->intern->strategy = _IOFBF;
stream->intern->fd = fd; stream->intern->syshd = *syshd;
stream->intern->print_ntotal = 0; stream->intern->print_ntotal = 0;
stream->intern->indicators.err = 0; stream->intern->indicators.err = 0;
stream->intern->indicators.eof = 0; stream->intern->indicators.eof = 0;
@ -1329,7 +1574,7 @@ es_deinitialize (estream_t stream)
/* Create a new stream object, initialize it. */ /* Create a new stream object, initialize it. */
static int static int
es_create (estream_t *stream, void *cookie, int fd, es_create (estream_t *stream, void *cookie, es_syshd_t *syshd,
es_cookie_io_functions_t functions, unsigned int modeflags, es_cookie_io_functions_t functions, unsigned int modeflags,
int with_locked_list) int with_locked_list)
{ {
@ -1361,7 +1606,7 @@ es_create (estream_t *stream, void *cookie, int fd,
stream_new->intern = stream_internal_new; stream_new->intern = stream_internal_new;
ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock); ESTREAM_MUTEX_INITIALIZE (stream_new->intern->lock);
es_initialize (stream_new, cookie, fd, functions, modeflags); es_initialize (stream_new, cookie, syshd, functions, modeflags);
err = es_list_add (stream_new, with_locked_list); err = es_list_add (stream_new, with_locked_list);
if (err) if (err)
@ -1385,9 +1630,9 @@ es_create (estream_t *stream, void *cookie, int fd,
/* Deinitialize a stream object and destroy it. */ /* Deinitialize a stream object and destroy it. */
static int static int
es_destroy (estream_t stream, int with_locked_list) do_close (estream_t stream, int with_locked_list)
{ {
int err = 0; int err;
if (stream) if (stream)
{ {
@ -1396,6 +1641,8 @@ es_destroy (estream_t stream, int with_locked_list)
mem_free (stream->intern); mem_free (stream->intern);
mem_free (stream); mem_free (stream);
} }
else
err = 0;
return err; return err;
} }
@ -1897,6 +2144,7 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
unsigned char *data; unsigned char *data;
size_t data_len; size_t data_len;
int err; int err;
es_syshd_t syshd;
line_new = NULL; line_new = NULL;
line_stream = NULL; line_stream = NULL;
@ -1910,7 +2158,8 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
if (err) if (err)
goto out; goto out;
err = es_create (&line_stream, line_stream_cookie, -1, memset (&syshd, 0, sizeof syshd);
err = es_create (&line_stream, line_stream_cookie, &syshd,
estream_functions_mem, O_RDWR, 0); estream_functions_mem, O_RDWR, 0);
if (err) if (err)
goto out; goto out;
@ -1996,7 +2245,7 @@ doreadline (estream_t ES__RESTRICT stream, size_t max_length,
out: out:
if (line_stream) if (line_stream)
es_destroy (line_stream, 0); do_close (line_stream, 0);
else if (line_stream_cookie) else if (line_stream_cookie)
es_func_mem_destroy (line_stream_cookie); es_func_mem_destroy (line_stream_cookie);
@ -2152,12 +2401,6 @@ es_opaque_ctrl (estream_t ES__RESTRICT stream, void *ES__RESTRICT opaque_new,
} }
static int
es_get_fd (estream_t stream)
{
return stream->intern->fd;
}
/* API. */ /* API. */
@ -2172,6 +2415,8 @@ es_init (void)
return err; return err;
} }
estream_t estream_t
es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode) es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
{ {
@ -2181,6 +2426,7 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
void *cookie; void *cookie;
int err; int err;
int fd; int fd;
es_syshd_t syshd;
stream = NULL; stream = NULL;
cookie = NULL; cookie = NULL;
@ -2193,9 +2439,12 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
err = es_func_file_create (&cookie, &fd, path, modeflags); err = es_func_file_create (&cookie, &fd, path, modeflags);
if (err) if (err)
goto out; goto out;
syshd.type = ES_SYSHD_FD;
syshd.u.fd = fd;
create_called = 1; create_called = 1;
err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags, 0); err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, 0);
if (err) if (err)
goto out; goto out;
@ -2211,6 +2460,7 @@ es_fopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode)
} }
estream_t estream_t
es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len, es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
unsigned int grow, unsigned int grow,
@ -2222,6 +2472,7 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
estream_t stream; estream_t stream;
void *cookie; void *cookie;
int err; int err;
es_syshd_t syshd;
cookie = 0; cookie = 0;
stream = NULL; stream = NULL;
@ -2237,8 +2488,10 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
if (err) if (err)
goto out; goto out;
memset (&syshd, 0, sizeof syshd);
create_called = 1; create_called = 1;
err = es_create (&stream, cookie, -1, estream_functions_mem, modeflags, 0); err = es_create (&stream, cookie, &syshd,
estream_functions_mem, modeflags, 0);
out: out:
@ -2249,12 +2502,14 @@ es_mopen (unsigned char *ES__RESTRICT data, size_t data_n, size_t data_len,
} }
estream_t estream_t
es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode) es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
{ {
unsigned int modeflags; unsigned int modeflags;
estream_t stream = NULL; estream_t stream = NULL;
void *cookie = NULL; void *cookie = NULL;
es_syshd_t syshd;
/* Memory streams are always read/write. We use MODE only to get /* Memory streams are always read/write. We use MODE only to get
the append flag. */ the append flag. */
@ -2269,14 +2524,15 @@ es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
memlimit)) memlimit))
return NULL; return NULL;
if (es_create (&stream, cookie, -1, estream_functions_mem, modeflags, 0)) memset (&syshd, 0, sizeof syshd);
if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, 0))
(*estream_functions_mem.func_close) (cookie); (*estream_functions_mem.func_close) (cookie);
return stream; return stream;
} }
estream_t estream_t
es_fopencookie (void *ES__RESTRICT cookie, es_fopencookie (void *ES__RESTRICT cookie,
const char *ES__RESTRICT mode, const char *ES__RESTRICT mode,
@ -2285,6 +2541,7 @@ es_fopencookie (void *ES__RESTRICT cookie,
unsigned int modeflags; unsigned int modeflags;
estream_t stream; estream_t stream;
int err; int err;
es_syshd_t syshd;
stream = NULL; stream = NULL;
modeflags = 0; modeflags = 0;
@ -2293,16 +2550,17 @@ es_fopencookie (void *ES__RESTRICT cookie,
if (err) if (err)
goto out; goto out;
err = es_create (&stream, cookie, -1, functions, modeflags, 0); memset (&syshd, 0, sizeof syshd);
err = es_create (&stream, cookie, &syshd, functions, modeflags, 0);
if (err) if (err)
goto out; goto out;
out: out:
return stream; return stream;
} }
estream_t estream_t
do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list) do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
{ {
@ -2311,6 +2569,7 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
estream_t stream; estream_t stream;
void *cookie; void *cookie;
int err; int err;
es_syshd_t syshd;
stream = NULL; stream = NULL;
cookie = NULL; cookie = NULL;
@ -2324,12 +2583,13 @@ do_fdopen (int filedes, const char *mode, int no_close, int with_locked_list)
if (err) if (err)
goto out; goto out;
syshd.type = ES_SYSHD_FD;
syshd.u.fd = filedes;
create_called = 1; create_called = 1;
err = es_create (&stream, cookie, filedes, estream_functions_fd, err = es_create (&stream, cookie, &syshd, estream_functions_fd,
modeflags, with_locked_list); modeflags, with_locked_list);
out: out:
if (err && create_called) if (err && create_called)
(*estream_functions_fd.func_close) (cookie); (*estream_functions_fd.func_close) (cookie);
@ -2350,6 +2610,7 @@ es_fdopen_nc (int filedes, const char *mode)
} }
estream_t estream_t
do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list) do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
{ {
@ -2358,6 +2619,7 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
estream_t stream; estream_t stream;
void *cookie; void *cookie;
int err; int err;
es_syshd_t syshd;
stream = NULL; stream = NULL;
cookie = NULL; cookie = NULL;
@ -2372,9 +2634,11 @@ do_fpopen (FILE *fp, const char *mode, int no_close, int with_locked_list)
err = es_func_fp_create (&cookie, fp, modeflags, no_close); err = es_func_fp_create (&cookie, fp, modeflags, no_close);
if (err) if (err)
goto out; goto out;
syshd.type = ES_SYSHD_FD;
syshd.u.fd = fp? fileno (fp): -1;
create_called = 1; create_called = 1;
err = es_create (&stream, cookie, fp? fileno (fp):-1, estream_functions_fp, err = es_create (&stream, cookie, &syshd, estream_functions_fp,
modeflags, with_locked_list); modeflags, with_locked_list);
out: out:
@ -2409,6 +2673,87 @@ es_fpopen_nc (FILE *fp, const char *mode)
} }
#ifdef HAVE_W32_SYSTEM
estream_t
do_w32open (HANDLE hd, const char *mode,
int no_close, int with_locked_list)
{
unsigned int modeflags;
int create_called = 0;
estream_t stream = NULL;
void *cookie = NULL;
int err;
es_syshd_t syshd;
err = es_convert_mode (mode, &modeflags);
if (err)
goto leave;
err = es_func_w32_create (&cookie, hd, modeflags, no_close);
if (err)
goto leave;
syshd.type = ES_SYSHD_HANDLE;
syshd.u.handle = hd;
create_called = 1;
err = es_create (&stream, cookie, &syshd, estream_functions_w32,
modeflags, with_locked_list);
leave:
if (err && create_called)
(*estream_functions_w32.func_close) (cookie);
return stream;
}
#endif /*HAVE_W32_SYSTEM*/
static estream_t
do_sysopen (es_syshd_t *syshd, const char *mode, int no_close)
{
estream_t stream;
switch (syshd->type)
{
case ES_SYSHD_FD:
case ES_SYSHD_SOCK:
stream = do_fdopen (syshd->u.fd, mode, no_close, 0);
break;
#ifdef HAVE_W32_SYSTEM
case ES_SYSHD_HANDLE:
stream = do_w32open (syshd->u.handle, mode, no_close, 0);
break;
#endif
/* FIXME: Support RVIDs under Wince? */
default:
_set_errno (EINVAL);
stream = NULL;
}
return stream;
}
/* On POSIX systems this function is an alias for es_fdopen. Under
Windows it uses the bare W32 API and thus a HANDLE instead of a
file descriptor. */
estream_t
es_sysopen (es_syshd_t *syshd, const char *mode)
{
return do_sysopen (syshd, mode, 0);
}
/* Same as es_sysopen but the handle/fd will not be closed by
es_fclose. */
estream_t
es_sysopen_nc (es_syshd_t *syshd, const char *mode)
{
return do_sysopen (syshd, mode, 1);
}
/* Set custom standard descriptors to be used for stdin, stdout and /* Set custom standard descriptors to be used for stdin, stdout and
stderr. This function needs to be called before any of the stderr. This function needs to be called before any of the
standard streams are accessed. */ standard streams are accessed. */
@ -2500,6 +2845,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
int create_called; int create_called;
void *cookie; void *cookie;
int fd; int fd;
es_syshd_t syshd;
cookie = NULL; cookie = NULL;
create_called = 0; create_called = 0;
@ -2516,8 +2862,10 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
if (err) if (err)
goto leave; goto leave;
syshd.type = ES_SYSHD_FD;
syshd.u.fd = fd;
create_called = 1; create_called = 1;
es_initialize (stream, cookie, fd, estream_functions_fd, modeflags); es_initialize (stream, cookie, &syshd, estream_functions_fd, modeflags);
leave: leave:
@ -2526,7 +2874,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
if (create_called) if (create_called)
es_func_fd_destroy (cookie); es_func_fd_destroy (cookie);
es_destroy (stream, 0); do_close (stream, 0);
stream = NULL; stream = NULL;
} }
else else
@ -2541,7 +2889,7 @@ es_freopen (const char *ES__RESTRICT path, const char *ES__RESTRICT mode,
/* FIXME? We don't support re-opening at the moment. */ /* FIXME? We don't support re-opening at the moment. */
_set_errno (EINVAL); _set_errno (EINVAL);
es_deinitialize (stream); es_deinitialize (stream);
es_destroy (stream, 0); do_close (stream, 0);
stream = NULL; stream = NULL;
} }
@ -2554,15 +2902,47 @@ es_fclose (estream_t stream)
{ {
int err; int err;
err = es_destroy (stream, 0); err = do_close (stream, 0);
return err; return err;
} }
int int
es_fileno_unlocked (estream_t stream) es_fileno_unlocked (estream_t stream)
{ {
return es_get_fd (stream); es_syshd_t syshd;
if (es_syshd (stream, &syshd))
return -1;
switch (syshd.type)
{
case ES_SYSHD_FD: return syshd.u.fd;
case ES_SYSHD_SOCK: return syshd.u.sock;
default:
_set_errno (EINVAL);
return -1;
}
}
/* Return the handle of a stream which has been opened by es_sysopen.
The caller needs to pass a structure which will be filled with the
sys handle. Return 0 on success or true on error and sets errno.
This is the unlocked version. */
int
es_syshd_unlocked (estream_t stream, es_syshd_t *syshd)
{
if (!stream || !syshd || stream->intern->syshd.type == ES_SYSHD_NONE)
{
if (syshd)
syshd->type = ES_SYSHD_NONE;
_set_errno (EINVAL);
return -1;
}
*syshd = stream->intern->syshd;
return 0;
} }
@ -2600,6 +2980,23 @@ es_fileno (estream_t stream)
} }
/* Return the handle of a stream which has been opened by es_sysopen.
The caller needs to pass a structure which will be filled with the
sys handle. Return 0 on success or true on error and sets errno.
This is the unlocked version. */
int
es_syshd (estream_t stream, es_syshd_t *syshd)
{
int ret;
ESTREAM_LOCK (stream);
ret = es_syshd_unlocked (stream, syshd);
ESTREAM_UNLOCK (stream);
return ret;
}
int int
es_feof_unlocked (estream_t stream) es_feof_unlocked (estream_t stream)
{ {
@ -3371,6 +3768,7 @@ es_tmpfile (void)
void *cookie; void *cookie;
int err; int err;
int fd; int fd;
es_syshd_t syshd;
create_called = 0; create_called = 0;
stream = NULL; stream = NULL;
@ -3388,11 +3786,12 @@ es_tmpfile (void)
if (err) if (err)
goto out; goto out;
syshd.type = ES_SYSHD_FD;
syshd.u.fd = fd;
create_called = 1; create_called = 1;
err = es_create (&stream, cookie, fd, estream_functions_fd, modeflags, 0); err = es_create (&stream, cookie, &syshd, estream_functions_fd, modeflags, 0);
out: out:
if (err) if (err)
{ {
if (create_called) if (create_called)

View File

@ -78,6 +78,8 @@
#define es_fopenmem _ESTREAM_PREFIX(es_fopenmem) #define es_fopenmem _ESTREAM_PREFIX(es_fopenmem)
#define es_fdopen _ESTREAM_PREFIX(es_fdopen) #define es_fdopen _ESTREAM_PREFIX(es_fdopen)
#define es_fdopen_nc _ESTREAM_PREFIX(es_fdopen_nc) #define es_fdopen_nc _ESTREAM_PREFIX(es_fdopen_nc)
#define es_sysopen _ESTREAM_PREFIX(es_sysopen)
#define es_sysopen_nc _ESTREAM_PREFIX(es_sysopen_nc)
#define es_fpopen _ESTREAM_PREFIX(es_fpopen) #define es_fpopen _ESTREAM_PREFIX(es_fpopen)
#define es_fpopen_nc _ESTREAM_PREFIX(es_fpopen_nc) #define es_fpopen_nc _ESTREAM_PREFIX(es_fpopen_nc)
#define _es_set_std_fd _ESTREAM_PREFIX(_es_set_std_fd) #define _es_set_std_fd _ESTREAM_PREFIX(_es_set_std_fd)
@ -211,6 +213,29 @@ typedef struct es_cookie_io_functions
es_cookie_close_function_t func_close; es_cookie_close_function_t func_close;
} es_cookie_io_functions_t; } es_cookie_io_functions_t;
enum es_syshd_types
{
ES_SYSHD_NONE, /* No system handle available. */
ES_SYSHD_FD, /* A file descriptor as returned by open(). */
ES_SYSHD_SOCK, /* A socket as returned by socket(). */
ES_SYSHD_RVID, /* A rendevous id (see libassuan's gpgcedev.c). */
ES_SYSHD_HANDLE /* A HANDLE object (Windows). */
};
typedef struct
{
enum es_syshd_types type;
union {
int fd;
int sock;
int rvid;
void *handle;
} u;
} es_syshd_t;
#ifndef _ESTREAM_GCC_A_PRINTF #ifndef _ESTREAM_GCC_A_PRINTF
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
@ -245,6 +270,8 @@ estream_t es_mopen (unsigned char *ES__RESTRICT data,
estream_t es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode); estream_t es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode);
estream_t es_fdopen (int filedes, const char *mode); estream_t es_fdopen (int filedes, const char *mode);
estream_t es_fdopen_nc (int filedes, const char *mode); estream_t es_fdopen_nc (int filedes, const char *mode);
estream_t es_sysopen (es_syshd_t *syshd, const char *mode);
estream_t es_sysopen_nc (es_syshd_t *syshd, const char *mode);
estream_t es_fpopen (FILE *fp, const char *mode); estream_t es_fpopen (FILE *fp, const char *mode);
estream_t es_fpopen_nc (FILE *fp, const char *mode); estream_t es_fpopen_nc (FILE *fp, const char *mode);
estream_t es_freopen (const char *ES__RESTRICT path, estream_t es_freopen (const char *ES__RESTRICT path,
@ -256,6 +283,8 @@ estream_t es_fopencookie (void *ES__RESTRICT cookie,
int es_fclose (estream_t stream); int es_fclose (estream_t stream);
int es_fileno (estream_t stream); int es_fileno (estream_t stream);
int es_fileno_unlocked (estream_t stream); int es_fileno_unlocked (estream_t stream);
int es_syshd (estream_t stream, es_syshd_t *syshd);
int es_syshd_unlocked (estream_t stream, es_syshd_t *syshd);
void _es_set_std_fd (int no, int fd); void _es_set_std_fd (int no, int fd);
estream_t _es_get_std_stream (int fd); estream_t _es_get_std_stream (int fd);

View File

@ -299,45 +299,95 @@ gnupg_create_outbound_pipe (int filedes[2])
} }
static gpg_error_t
create_pipe_and_estream (int filedes[2], estream_t *r_fp,
gpg_err_source_t errsource)
{
gpg_error_t err;
if (pipe (filedes) == -1)
{
err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
filedes[0] = filedes[1] = -1;
*r_fp = NULL;
return err;
}
*r_fp = es_fdopen (filedes[0], "r");
if (!*r_fp)
{
err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
log_error (_("error creating a stream for a pipe: %s\n"),
gpg_strerror (err));
close (filedes[0]);
close (filedes[1]);
filedes[0] = filedes[1] = -1;
return err;
}
return 0;
}
/* Fork and exec the PGMNAME, see exechelp.h for details. */ /* Fork and exec the PGMNAME, see exechelp.h for details. */
gpg_error_t gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[], gnupg_spawn_process (const char *pgmname, const char *argv[],
estream_t infile, estream_t outfile, gpg_err_source_t errsource,
void (*preexec)(void), unsigned int flags, void (*preexec)(void), unsigned int flags,
estream_t *statusfile, pid_t *pid) estream_t infp,
estream_t *r_outfp,
estream_t *r_errfp,
pid_t *pid)
{ {
gpg_error_t err; gpg_error_t err;
int fd, fdout, rp[2]; int infd = -1;
int outpipe[2] = {-1, -1};
int errpipe[2] = {-1, -1};
estream_t outfp = NULL;
estream_t errfp = NULL;
(void)flags; /* Currently not used. */ (void)flags; /* Currently not used. */
*statusfile = NULL; if (r_outfp)
*pid = (pid_t)(-1); *r_outfp = NULL;
if (r_errfp)
*r_errfp = NULL;
*pid = (pid_t)(-1); /* Always required. */
if (infile) if (infp)
{ {
es_fflush (infile); es_fflush (infp);
es_rewind (infile); es_rewind (infp);
fd = es_fileno (infile); infd = es_fileno (infp);
if (infd == -1)
return gpg_err_make (errsource, GPG_ERR_INV_VALUE);
} }
else
fd = -1;
if (outfile) if (r_outfp)
fdout = es_fileno (outfile);
else
fdout = -1;
if ((infile && fd == -1) || (outfile && fdout == -1))
log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n");
if (pipe (rp) == -1)
{ {
err = gpg_error_from_syserror (); err = create_pipe_and_estream (outpipe, &outfp, errsource);
log_error (_("error creating a pipe: %s\n"), strerror (errno)); if (err)
return err; return err;
} }
if (r_errfp)
{
err = create_pipe_and_estream (errpipe, &errfp, errsource);
if (err)
{
if (outfp)
es_fclose (outfp);
else if (outpipe[0] != -1)
close (outpipe[0]);
if (outpipe[1] != -1)
close (outpipe[1]);
return err;
}
}
#ifdef USE_GNU_PTH #ifdef USE_GNU_PTH
*pid = pth_fork? pth_fork () : fork (); *pid = pth_fork? pth_fork () : fork ();
#else #else
@ -345,33 +395,45 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
#endif #endif
if (*pid == (pid_t)(-1)) if (*pid == (pid_t)(-1))
{ {
err = gpg_error_from_syserror (); err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
log_error (_("error forking process: %s\n"), strerror (errno)); log_error (_("error forking process: %s\n"), gpg_strerror (err));
close (rp[0]);
close (rp[1]); if (outfp)
es_fclose (outfp);
else if (outpipe[0] != -1)
close (outpipe[0]);
if (outpipe[1] != -1)
close (outpipe[1]);
if (errfp)
es_fclose (errfp);
else if (errpipe[0] != -1)
close (errpipe[0]);
if (errpipe[1] != -1)
close (errpipe[1]);
return err; return err;
} }
if (!*pid) if (!*pid)
{ {
/* This is the child. */
gcry_control (GCRYCTL_TERM_SECMEM); gcry_control (GCRYCTL_TERM_SECMEM);
/* Run child. */ es_fclose (outfp);
do_exec (pgmname, argv, fd, fdout, rp[1], preexec); es_fclose (errfp);
do_exec (pgmname, argv, infd, outpipe[1], errpipe[1], preexec);
/*NOTREACHED*/ /*NOTREACHED*/
} }
/* Parent. */ /* This is the parent. */
close (rp[1]); if (outpipe[1] != -1)
close (outpipe[1]);
if (errpipe[1] != -1)
close (errpipe[1]);
*statusfile = es_fdopen (rp[0], "r"); if (r_outfp)
if (!*statusfile) *r_outfp = outfp;
{ if (r_errfp)
err = gpg_error_from_syserror (); *r_errfp = errfp;
log_error (_("can't fdopen pipe for reading: %s\n"), strerror (errno));
kill (*pid, SIGTERM);
*pid = (pid_t)(-1);
return err;
}
return 0; return 0;
} }

View File

@ -257,7 +257,7 @@ build_w32_commandline (const char *pgmname, const char * const *argv,
/* Create pipe where one end is inheritable: With an INHERIT_IDX of 0 /* Create pipe where one end is inheritable: With an INHERIT_IDX of 0
the read end is inheritable, with 1 the write end is inheritable. */ the read end is inheritable, with 1 the write end is inheritable. */
static int static int
create_inheritable_pipe (int filedes[2], int inherit_idx) create_inheritable_pipe (HANDLE filedes[2], int inherit_idx)
{ {
HANDLE r, w, h; HANDLE r, w, h;
SECURITY_ATTRIBUTES sec_attr; SECURITY_ATTRIBUTES sec_attr;
@ -290,8 +290,8 @@ create_inheritable_pipe (int filedes[2], int inherit_idx)
r = h; r = h;
} }
filedes[0] = handle_to_fd (r); filedes[0] = r;
filedes[1] = handle_to_fd (w); filedes[1] = w;
return 0; return 0;
} }
@ -315,27 +315,27 @@ static gpg_error_t
do_create_pipe (int filedes[2], int inherit_idx) do_create_pipe (int filedes[2], int inherit_idx)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
int fds[2]; HANDLE fds[2];
filedes[0] = filedes[1] = -1; filedes[0] = filedes[1] = -1;
err = gpg_error (GPG_ERR_GENERAL); err = gpg_error (GPG_ERR_GENERAL);
if (!create_inheritable_pipe (fds, inherit_idx)) if (!create_inheritable_pipe (fds, inherit_idx))
{ {
filedes[0] = _open_osfhandle (fds[0], 0); filedes[0] = _open_osfhandle (handle_to_fd (fds[0]), 0);
if (filedes[0] == -1) if (filedes[0] == -1)
{ {
log_error ("failed to translate osfhandle %p\n", (void*)fds[0]); log_error ("failed to translate osfhandle %p\n", fds[0]);
CloseHandle (fd_to_handle (fds[1])); CloseHandle (fds[1]);
} }
else else
{ {
filedes[1] = _open_osfhandle (fds[1], 1); filedes[1] = _open_osfhandle (handle_to_fd (fds[1]), 1);
if (filedes[1] == -1) if (filedes[1] == -1)
{ {
log_error ("failed to translate osfhandle %p\n", (void*)fds[1]); log_error ("failed to translate osfhandle %p\n", fds[1]);
close (filedes[0]); close (filedes[0]);
filedes[0] = -1; filedes[0] = -1;
CloseHandle (fd_to_handle (fds[1])); CloseHandle (fds[1]);
} }
else else
err = 0; err = 0;
@ -365,9 +365,12 @@ gnupg_create_outbound_pipe (int filedes[2])
/* Fork and exec the PGMNAME, see exechelp.h for details. */ /* Fork and exec the PGMNAME, see exechelp.h for details. */
gpg_error_t gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[], gnupg_spawn_process (const char *pgmname, const char *argv[],
estream_t infile, estream_t outfile, gpg_err_source_t errsource,
void (*preexec)(void), unsigned int flags, void (*preexec)(void), unsigned int flags,
estream_t *statusfile, pid_t *pid) estream_t infp,
estream_t *r_outfp,
estream_t *r_errfp,
pid_t *pid)
{ {
gpg_error_t err; gpg_error_t err;
SECURITY_ATTRIBUTES sec_attr; SECURITY_ATTRIBUTES sec_attr;
@ -381,32 +384,103 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
STARTUPINFO si; STARTUPINFO si;
int cr_flags; int cr_flags;
char *cmdline; char *cmdline;
int fd, fdout, rp[2]; HANDLE inhandle = INVALID_HANDLE_VALUE;
HANDLE nullhd[2]; HANDLE outpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
HANDLE errpipe[2] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
estream_t outfp = NULL;
estream_t errfp = NULL;
HANDLE nullhd[3] = {INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE,
INVALID_HANDLE_VALUE};
int i; int i;
es_syshd_t syshd;
(void)preexec; if (r_outfp)
*r_outfp = NULL;
/* Setup return values. */ if (r_errfp)
*statusfile = NULL; *r_errfp = NULL;
*pid = (pid_t)(-1); *pid = (pid_t)(-1); /* Always required. */
if (infile) if (infp)
{ {
es_fflush (infile); es_fflush (infp);
es_rewind (infile); es_rewind (infp);
fd = _get_osfhandle (es_fileno (infile)); es_syshd (infp, &syshd);
switch (syshd.type)
{
case ES_SYSHD_FD:
inhandle = (HANDLE)_get_osfhandle (syshd.u.fd);
break;
case ES_SYSHD_SOCK:
inhandle = (HANDLE)_get_osfhandle (syshd.u.sock);
break;
case ES_SYSHD_HANDLE:
inhandle = syshd.u.handle;
break;
default:
inhandle = INVALID_HANDLE_VALUE;
break;
}
if (inhandle == INVALID_HANDLE_VALUE)
return gpg_err_make (errsource, GPG_ERR_INV_VALUE);
/* FIXME: In case we can't get a system handle (e.g. due to
es_fopencookie we should create a piper and a feeder
thread. */
} }
else
fd = -1;
if (outfile) if (r_outfp)
fdout = _get_osfhandle (es_fileno (outfile)); {
else if (create_inheritable_pipe (outpipe, 1))
fdout = -1; {
err = gpg_err_make (errsource, GPG_ERR_GENERAL);
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
return err;
}
if ( (infile && fd == -1) || (outfile && fdout == -1)) syshd.type = ES_SYSHD_HANDLE;
log_fatal ("no file descriptor for file passed to gnupg_spawn_process\n"); syshd.u.handle = outpipe[0];
outfp = es_sysopen (&syshd, "r");
if (!outfp)
{
err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
log_error (_("error creating a stream for a pipe: %s\n"),
gpg_strerror (err));
CloseHandle (outpipe[0]);
CloseHandle (outpipe[1]);
outpipe[0] = outpipe[1] = INVALID_HANDLE_VALUE;
return err;
}
}
if (r_errfp)
{
if (create_inheritable_pipe (errpipe, 1))
{
err = gpg_err_make (errsource, GPG_ERR_GENERAL);
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err));
return err;
}
syshd.type = ES_SYSHD_HANDLE;
syshd.u.handle = errpipe[0];
errfp = es_sysopen (&syshd, "r");
if (!errfp)
{
err = gpg_err_make (errsource, gpg_err_code_from_syserror ());
log_error (_("error creating a stream for a pipe: %s\n"),
gpg_strerror (err));
CloseHandle (errpipe[0]);
CloseHandle (errpipe[1]);
errpipe[0] = errpipe[1] = INVALID_HANDLE_VALUE;
if (outfp)
es_fclose (outfp);
else if (outpipe[0] != INVALID_HANDLE_VALUE)
CloseHandle (outpipe[0]);
if (outpipe[1] != INVALID_HANDLE_VALUE)
CloseHandle (outpipe[1]);
return err;
}
}
/* Prepare security attributes. */ /* Prepare security attributes. */
memset (&sec_attr, 0, sizeof sec_attr ); memset (&sec_attr, 0, sizeof sec_attr );
@ -418,27 +492,24 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
if (err) if (err)
return err; return err;
/* Create a pipe. */ if (inhandle != INVALID_HANDLE_VALUE)
if (create_inheritable_pipe (rp, 1)) nullhd[0] = w32_open_null (0);
{ if (outpipe[1] != INVALID_HANDLE_VALUE)
err = gpg_error (GPG_ERR_GENERAL); nullhd[1] = w32_open_null (0);
log_error (_("error creating a pipe: %s\n"), gpg_strerror (err)); if (errpipe[1] != INVALID_HANDLE_VALUE)
xfree (cmdline); nullhd[2] = w32_open_null (0);
return err;
}
nullhd[0] = fd == -1? w32_open_null (0) : INVALID_HANDLE_VALUE;
nullhd[1] = fdout == -1? w32_open_null (1) : INVALID_HANDLE_VALUE;
/* Start the process. Note that we can't run the PREEXEC function /* Start the process. Note that we can't run the PREEXEC function
because this would change our own environment. */ because this might change our own environment. */
(void)preexec;
memset (&si, 0, sizeof si); memset (&si, 0, sizeof si);
si.cb = sizeof (si); si.cb = sizeof (si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE; si.wShowWindow = DEBUG_W32_SPAWN? SW_SHOW : SW_MINIMIZE;
si.hStdInput = fd == -1? nullhd[0] : fd_to_handle (fd); si.hStdInput = inhandle == INVALID_HANDLE_VALUE? nullhd[0] : inhandle;
si.hStdOutput = fdout == -1? nullhd[1] : fd_to_handle (fdout); si.hStdOutput = outpipe[1] == INVALID_HANDLE_VALUE? nullhd[1] : outpipe[1];
si.hStdError = fd_to_handle (rp[1]); si.hStdError = errpipe[1] == INVALID_HANDLE_VALUE? nullhd[2] : errpipe[1];
cr_flags = (CREATE_DEFAULT_ERROR_MODE cr_flags = (CREATE_DEFAULT_ERROR_MODE
| ((flags & 128)? DETACHED_PROCESS : 0) | ((flags & 128)? DETACHED_PROCESS : 0)
@ -459,9 +530,19 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
{ {
log_error ("CreateProcess failed: %s\n", w32_strerror (-1)); log_error ("CreateProcess failed: %s\n", w32_strerror (-1));
xfree (cmdline); xfree (cmdline);
CloseHandle (fd_to_handle (rp[0])); if (outfp)
CloseHandle (fd_to_handle (rp[1])); es_fclose (outfp);
return gpg_error (GPG_ERR_GENERAL); else if (outpipe[0] != INVALID_HANDLE_VALUE)
CloseHandle (outpipe[0]);
if (outpipe[1] != INVALID_HANDLE_VALUE)
CloseHandle (outpipe[1]);
if (errfp)
es_fclose (errfp);
else if (errpipe[0] != INVALID_HANDLE_VALUE)
CloseHandle (errpipe[0]);
if (errpipe[1] != INVALID_HANDLE_VALUE)
CloseHandle (errpipe[1]);
return gpg_err_make (errsource, GPG_ERR_GENERAL);
} }
xfree (cmdline); xfree (cmdline);
cmdline = NULL; cmdline = NULL;
@ -471,17 +552,21 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
if (nullhd[i] != INVALID_HANDLE_VALUE) if (nullhd[i] != INVALID_HANDLE_VALUE)
CloseHandle (nullhd[i]); CloseHandle (nullhd[i]);
/* Close the other end of the pipe. */ /* Close the inherited ends of the pipes. */
CloseHandle (fd_to_handle (rp[1])); if (outpipe[1] != INVALID_HANDLE_VALUE)
CloseHandle (outpipe[1]);
/* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */ if (errpipe[1] != INVALID_HANDLE_VALUE)
/* " dwProcessID=%d dwThreadId=%d\n", */ CloseHandle (errpipe[1]);
/* pi.hProcess, pi.hThread, */
/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
/* log_debug ("CreateProcess ready: hProcess=%p hThread=%p" */
/* " dwProcessID=%d dwThreadId=%d\n", */
/* pi.hProcess, pi.hThread, */
/* (int) pi.dwProcessId, (int) pi.dwThreadId); */
/* log_debug (" outfp=%p errfp=%p\n", outfp, errfp); */
/* Fixme: For unknown reasons AllowSetForegroundWindow returns an /* Fixme: For unknown reasons AllowSetForegroundWindow returns an
invalid argument error if we pass the correct processID to invalid argument error if we pass it the correct processID. As a
it. As a workaround we use -1 (ASFW_ANY). */ workaround we use -1 (ASFW_ANY). */
if ( (flags & 64) ) if ( (flags & 64) )
gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/); gnupg_allow_set_foregound_window ((pid_t)(-1)/*pi.dwProcessId*/);
@ -489,22 +574,10 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
ResumeThread (pi.hThread); ResumeThread (pi.hThread);
CloseHandle (pi.hThread); CloseHandle (pi.hThread);
{ if (r_outfp)
int x; *r_outfp = outfp;
if (r_errfp)
x = _open_osfhandle (rp[0], 0); *r_errfp = errfp;
if (x == -1)
log_error ("failed to translate osfhandle %p\n", (void*)rp[0] );
else
*statusfile = es_fdopen (x, "r");
}
if (!*statusfile)
{
err = gpg_error_from_syserror ();
log_error (_("can't fdopen pipe for reading: %s\n"), gpg_strerror (err));
CloseHandle (pi.hProcess);
return err;
}
*pid = handle_to_pid (pi.hProcess); *pid = handle_to_pid (pi.hProcess);
return 0; return 0;

View File

@ -83,7 +83,7 @@ struct feeder_thread_parms
}; };
/* The thread started by start_feeded. */ /* The thread started by start_feede3. */
static void * static void *
feeder_thread (void *arg) feeder_thread (void *arg)
{ {
@ -485,10 +485,14 @@ create_process (const char *pgmname, const char *cmdline,
/* Fork and exec the PGMNAME, see exechelp.h for details. */ /* Fork and exec the PGMNAME, see exechelp.h for details. */
gpg_error_t gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[], gnupg_spawn_process (const char *pgmname, const char *argv[],
estream_t infile, estream_t outfile, gpg_err_source_t errsource,
void (*preexec)(void), unsigned int flags, void (*preexec)(void), unsigned int flags,
estream_t *statusfile, pid_t *pid) estream_t infp,
estream_t *r_outfp,
estream_t *r_errfp,
pid_t *pid)
{ {
#if 0
gpg_error_t err; gpg_error_t err;
PROCESS_INFORMATION pi = {NULL }; PROCESS_INFORMATION pi = {NULL };
char *cmdline; char *cmdline;
@ -598,7 +602,9 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
*pid = handle_to_pid (pi.hProcess); *pid = handle_to_pid (pi.hProcess);
return 0; return 0;
#else
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#endif
} }

View File

@ -52,15 +52,24 @@ gpg_error_t gnupg_create_inbound_pipe (int filedes[2]);
gpg_error_t gnupg_create_outbound_pipe (int filedes[2]); gpg_error_t gnupg_create_outbound_pipe (int filedes[2]);
/* Fork and exec the PGMNAME, connect the file descriptor of INFILE to /* Fork and exec the PGMNAME. If INFP is NULL connect /dev/null to
stdin, write the output to OUTFILE. INFILE or PUTFILE may be NULL stdin of the new process; if it is not NULL connect the file
to connect thenm to /dev/null. Returns a new stream in STATUSFILE descriptor retrieved from INFP to stdin. If R_OUTFP is NULL
for stderr and the pid of the process in PID. The arguments for the connect stdout of the new process to /dev/null; if it is not NULL
process are expected in the NULL terminated array ARGV. The store the address of a pointer to a new estream there. If R_ERRFP
program name itself should not be included there. If PREEXEC is is NULL connect stderr of the new process to /dev/null; if it is
not NULL, that function will be called right before the exec. not NULL store the address of a pointer to a new estream there. On
Calling gnupg_wait_process and gnupg_release_process is required. success the pid of the new process is stored at PID. On error -1
Returns 0 on success or an error code. is stored at PID and if R_OUTFP or R_ERRFP are not NULL, NULL is
stored there.
The arguments for the process are expected in the NULL terminated
array ARGV. The program name itself should not be included there.
If PREEXEC is not NULL, the given function will be called right
before the exec.
Returns 0 on success or an error code. Calling gnupg_wait_process
and gnupg_release_process is required if the function succeeded.
FLAGS is a bit vector: FLAGS is a bit vector:
@ -74,10 +83,14 @@ gpg_error_t gnupg_create_outbound_pipe (int filedes[2]);
allows SetForegroundWindow for all childs of this process. allows SetForegroundWindow for all childs of this process.
*/ */
gpg_error_t gnupg_spawn_process (const char *pgmname, const char *argv[], gpg_error_t
estream_t infile, estream_t outfile, gnupg_spawn_process (const char *pgmname, const char *argv[],
void (*preexec)(void), unsigned int flags, gpg_err_source_t errsource,
estream_t *statusfile, pid_t *pid); void (*preexec)(void), unsigned int flags,
estream_t infp,
estream_t *r_outfp,
estream_t *r_errfp,
pid_t *pid);
/* Simplified version of gnupg_spawn_process. This function forks and /* Simplified version of gnupg_spawn_process. This function forks and

View File

@ -1,5 +1,16 @@
2010-08-20 Werner Koch <wk@g10code.com>
* gpgconf-comp.c (collect_error_output): Remove extra CRs.
2010-08-19 Werner Koch <wk@g10code.com> 2010-08-19 Werner Koch <wk@g10code.com>
* gpgconf.c (main): Fix --check-options.
* gpgconf-comp.c (gc_component_check_options): Replace
gnupg_spawn_process_fd by gnupg_spawn_process.
(retrieve_options_from_program): Ditto.
(collect_error_output): Change to use estream.
* gpgconf-comp.c: Add new backend and component for PINENTRY. * gpgconf-comp.c: Add new backend and component for PINENTRY.
(gc_component_check_options): Use --version to test the pinentry. (gc_component_check_options): Use --version to test the pinentry.
(gc_component_retrieve_options, gc_component_change_options): (gc_component_retrieve_options, gc_component_change_options):

View File

@ -1363,14 +1363,12 @@ all_digits_p (const char *p, size_t len)
} }
/* Collect all error lines from file descriptor FD. Only lines /* Collect all error lines from stream FP. Only lines prefixed with
prefixed with TAG are considered. Close that file descriptor TAG are considered. Returns a list of error line items (which may
then. Returns a list of error line items (which may be empty). be empty). There is no error return. */
There is no error return. */
static error_line_t static error_line_t
collect_error_output (int fd, const char *tag) collect_error_output (estream_t fp, const char *tag)
{ {
FILE *fp;
char buffer[1024]; char buffer[1024];
char *p, *p2, *p3; char *p, *p2, *p3;
int c, cont_line; int c, cont_line;
@ -1378,15 +1376,11 @@ collect_error_output (int fd, const char *tag)
error_line_t eitem, errlines, *errlines_tail; error_line_t eitem, errlines, *errlines_tail;
size_t taglen = strlen (tag); size_t taglen = strlen (tag);
fp = fdopen (fd, "r");
if (!fp)
gc_error (1, errno, "can't fdopen pipe for reading");
errlines = NULL; errlines = NULL;
errlines_tail = &errlines; errlines_tail = &errlines;
pos = 0; pos = 0;
cont_line = 0; cont_line = 0;
while ((c=getc (fp)) != EOF) while ((c=es_getc (fp)) != EOF)
{ {
buffer[pos++] = c; buffer[pos++] = c;
if (pos >= sizeof buffer - 5 || c == '\n') if (pos >= sizeof buffer - 5 || c == '\n')
@ -1401,6 +1395,7 @@ collect_error_output (int fd, const char *tag)
p = buffer + taglen + 1; p = buffer + taglen + 1;
while (*p == ' ' || *p == '\t') while (*p == ' ' || *p == '\t')
p++; p++;
trim_trailing_spaces (p); /* Get rid of extra CRs. */
if (!*p) if (!*p)
; /* Empty lines are ignored. */ ; /* Empty lines are ignored. */
else if ( (p2 = strchr (p, ':')) && (p3 = strchr (p2+1, ':')) else if ( (p2 = strchr (p, ':')) && (p3 = strchr (p2+1, ':'))
@ -1445,8 +1440,6 @@ collect_error_output (int fd, const char *tag)
} }
/* We ignore error lines not terminated by a LF. */ /* We ignore error lines not terminated by a LF. */
fclose (fp);
return errlines; return errlines;
} }
@ -1466,14 +1459,9 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
int i; int i;
pid_t pid; pid_t pid;
int exitcode; int exitcode;
int filedes[2]; estream_t errfp;
error_line_t errlines; error_line_t errlines;
/* We use a temporary file to collect the error output. It would be
better to use a pipe here but as of now we have no suitable
fucntion to create a portable pipe outside of exechelp. Thus it
is easier to use the tempfile approach. */
for (backend = 0; backend < GC_BACKEND_NR; backend++) for (backend = 0; backend < GC_BACKEND_NR; backend++)
backend_seen[backend] = 0; backend_seen[backend] = 0;
@ -1510,23 +1498,15 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
argv[i++] = "--gpgconf-test"; argv[i++] = "--gpgconf-test";
argv[i++] = NULL; argv[i++] = NULL;
err = gnupg_create_inbound_pipe (filedes);
if (err)
gc_error (1, 0, _("error creating a pipe: %s\n"),
gpg_strerror (err));
result = 0; result = 0;
errlines = NULL; errlines = NULL;
if (gnupg_spawn_process_fd (pgmname, argv, -1, -1, filedes[1], &pid)) err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT, NULL, 0,
{ NULL, NULL, &errfp, &pid);
close (filedes[0]); if (err)
close (filedes[1]); result |= 1; /* Program could not be run. */
result |= 1; /* Program could not be run. */
}
else else
{ {
close (filedes[1]); errlines = collect_error_output (errfp,
errlines = collect_error_output (filedes[0],
gc_component[component].name); gc_component[component].name);
if (gnupg_wait_process (pgmname, pid, 1, &exitcode)) if (gnupg_wait_process (pgmname, pid, 1, &exitcode))
{ {
@ -1536,6 +1516,7 @@ gc_component_check_options (int component, estream_t out, const char *conf_file)
result |= 2; /* Program returned an error. */ result |= 2; /* Program returned an error. */
} }
gnupg_release_process (pid); gnupg_release_process (pid);
es_fclose (errfp);
} }
/* If the program could not be run, we can't tell whether /* If the program could not be run, we can't tell whether
@ -1839,41 +1820,32 @@ static void
retrieve_options_from_program (gc_component_t component, gc_backend_t backend) retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
{ {
gpg_error_t err; gpg_error_t err;
int filedes[2];
const char *pgmname; const char *pgmname;
const char *argv[2]; const char *argv[2];
estream_t outfp;
int exitcode; int exitcode;
pid_t pid; pid_t pid;
char *line = NULL; char *line = NULL;
size_t line_len = 0; size_t line_len = 0;
ssize_t length; ssize_t length;
FILE *config; estream_t config;
char *config_filename; char *config_filename;
err = gnupg_create_inbound_pipe (filedes);
if (err)
gc_error (1, 0, _("error creating a pipe: %s\n"), gpg_strerror (err));
pgmname = (gc_backend[backend].module_name pgmname = (gc_backend[backend].module_name
? gnupg_module_name (gc_backend[backend].module_name) ? gnupg_module_name (gc_backend[backend].module_name)
: gc_backend[backend].program ); : gc_backend[backend].program );
argv[0] = "--gpgconf-list"; argv[0] = "--gpgconf-list";
argv[1] = NULL; argv[1] = NULL;
err = gnupg_spawn_process_fd (pgmname, argv, -1, filedes[1], -1, &pid); err = gnupg_spawn_process (pgmname, argv, GPG_ERR_SOURCE_DEFAULT, NULL, 0,
NULL, &outfp, NULL, &pid);
if (err) if (err)
{ {
close (filedes[0]);
close (filedes[1]);
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));
} }
close (filedes[1]);
config = fdopen (filedes[0], "r");
if (!config)
gc_error (1, errno, "can't fdopen pipe for reading");
while ((length = read_line (config, &line, &line_len, NULL)) > 0) while ((length = es_read_line (outfp, &line, &line_len, NULL)) > 0)
{ {
gc_option_t *option; gc_option_t *option;
char *linep; char *linep;
@ -1942,9 +1914,9 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
option->default_value = xstrdup (default_value); option->default_value = xstrdup (default_value);
} }
} }
if (length < 0 || ferror (config)) if (length < 0 || es_ferror (outfp))
gc_error (1, errno, "error reading from %s",pgmname); gc_error (1, errno, "error reading from %s", pgmname);
if (fclose (config) && ferror (config)) if (es_fclose (outfp) && es_ferror (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_wait_process (pgmname, pid, 1, &exitcode);
@ -1957,13 +1929,13 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
/* At this point, we can parse the configuration file. */ /* At this point, we can parse the configuration file. */
config_filename = get_config_filename (component, backend); config_filename = get_config_filename (component, backend);
config = fopen (config_filename, "r"); config = es_fopen (config_filename, "r");
if (!config) if (!config)
gc_error (0, errno, "warning: can not open config file %s", gc_error (0, errno, "warning: can not open config file %s",
config_filename); config_filename);
else else
{ {
while ((length = read_line (config, &line, &line_len, NULL)) > 0) while ((length = es_read_line (config, &line, &line_len, NULL)) > 0)
{ {
char *name; char *name;
char *value; char *value;
@ -2044,9 +2016,9 @@ retrieve_options_from_program (gc_component_t component, gc_backend_t backend)
} }
} }
if (length < 0 || ferror (config)) if (length < 0 || es_ferror (config))
gc_error (1, errno, "error reading from %s", config_filename); gc_error (1, errno, "error reading from %s", config_filename);
if (fclose (config) && ferror (config)) if (es_fclose (config) && es_ferror (config))
gc_error (1, errno, "error closing %s", config_filename); gc_error (1, errno, "error closing %s", config_filename);
} }

View File

@ -226,15 +226,18 @@ main (int argc, char **argv)
es_putc ('\n', es_stderr); es_putc ('\n', es_stderr);
exit (1); exit (1);
} }
gc_component_retrieve_options (idx); if (cmd == aCheckOptions)
if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
exit (1);
if (cmd == aListOptions)
gc_component_list_options (idx, get_outfp (&outfp));
else if (cmd == aChangeOptions)
gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
else
gc_component_check_options (idx, get_outfp (&outfp), NULL); gc_component_check_options (idx, get_outfp (&outfp), NULL);
else
{
gc_component_retrieve_options (idx);
if (gc_process_gpgconf_conf (NULL, 1, 0, NULL))
exit (1);
if (cmd == aListOptions)
gc_component_list_options (idx, get_outfp (&outfp));
else if (cmd == aChangeOptions)
gc_component_change_options (idx, es_stdin, get_outfp (&outfp));
}
} }
break; break;