1
/* posix-io.c - Posix I/O functions
2
Copyright (C) 2000 Werner Koch (dd9jn)
3
Copyright (C) 2001, 2002, 2004, 2005, 2007 g10 Code GmbH
5
This file is part of GPGME.
7
GPGME is free software; you can redistribute it and/or modify it
8
under the terms of the GNU Lesser General Public License as
9
published by the Free Software Foundation; either version 2.1 of
10
the License, or (at your option) any later version.
12
GPGME is distributed in the hope that it will be useful, but
13
WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
Lesser General Public License for more details.
17
You should have received a copy of the GNU Lesser General Public
18
License along with this program; if not, write to the Free Software
19
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
34
#include <sys/types.h>
46
_gpgme_io_subsystem_init (void)
50
sigaction (SIGPIPE, NULL, &act);
51
if (act.sa_handler == SIG_DFL)
53
act.sa_handler = SIG_IGN;
54
sigemptyset (&act.sa_mask);
56
sigaction (SIGPIPE, &act, NULL);
61
/* Write the printable version of FD to the buffer BUF of length
62
BUFLEN. The printable version is the representation on the command
63
line that the child process expects. */
65
_gpgme_io_fd2str (char *buf, int buflen, int fd)
67
return snprintf (buf, buflen, "%d", fd);
73
_gpgme_close_notify_handler_t handler;
79
_gpgme_io_read (int fd, void *buffer, size_t count)
82
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
83
"buffer=%p, count=%u", buffer, count);
87
nread = _gpgme_ath_read (fd, buffer, count);
89
while (nread == -1 && errno == EINTR);
91
TRACE_LOGBUF (buffer, nread);
92
return TRACE_SYSRES (nread);
97
_gpgme_io_write (int fd, const void *buffer, size_t count)
100
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
101
"buffer=%p, count=%u", buffer, count);
102
TRACE_LOGBUF (buffer, count);
106
nwritten = _gpgme_ath_write (fd, buffer, count);
108
while (nwritten == -1 && errno == EINTR);
110
return TRACE_SYSRES (nwritten);
115
_gpgme_io_pipe (int filedes[2], int inherit_idx)
119
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
120
"inherit_idx=%i (GPGME uses it for %s)",
121
inherit_idx, inherit_idx ? "reading" : "writing");
123
err = pipe (filedes);
125
return TRACE_SYSRES (err);
127
/* FIXME: Should get the old flags first. */
128
err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
137
return TRACE_SYSRES (err);
139
return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
144
_gpgme_io_close (int fd)
148
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
153
return TRACE_SYSRES (-1);
156
/* First call the notify handler. */
157
if (fd >= 0 && fd < (int) DIM (notify_table))
159
if (notify_table[fd].handler)
161
TRACE_LOG2 ("invoking close handler %p/%p",
162
notify_table[fd].handler, notify_table[fd].value);
163
notify_table[fd].handler (fd, notify_table[fd].value);
164
notify_table[fd].handler = NULL;
165
notify_table[fd].value = NULL;
168
/* Then do the close. */
170
return TRACE_SYSRES (res);
175
_gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
178
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
179
"close_handler=%p/%p", handler, value);
183
if (fd < 0 || fd >= (int) DIM (notify_table))
186
return TRACE_SYSRES (-1);
188
notify_table[fd].handler = handler;
189
notify_table[fd].value = value;
190
return TRACE_SYSRES (0);
195
_gpgme_io_set_nonblocking (int fd)
199
TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
201
flags = fcntl (fd, F_GETFL, 0);
203
return TRACE_SYSRES (-1);
205
res = fcntl (fd, F_SETFL, flags);
206
return TRACE_SYSRES (res);
211
_gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
217
if (_gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG) == pid)
219
if (WIFSIGNALED (status))
221
*r_status = 4; /* Need some value here. */
222
*r_signal = WTERMSIG (status);
224
else if (WIFEXITED (status))
225
*r_status = WEXITSTATUS (status);
227
*r_status = 4; /* Oops. */
234
/* Returns 0 on success, -1 on error. */
236
_gpgme_io_spawn (const char *path, char **argv,
237
struct spawn_fd_item_s *fd_child_list,
238
struct spawn_fd_item_s *fd_parent_list)
244
TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
249
TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
255
return TRACE_SYSRES (-1);
259
/* Intermediate child to prevent zombie processes. */
260
if ((pid = fork ()) == 0)
264
int duped_stderr = 0;
266
/* First close all fds which will not be duped. */
267
for (i=0; fd_child_list[i].fd != -1; i++)
268
if (fd_child_list[i].dup_to == -1)
269
close (fd_child_list[i].fd);
271
/* And now dup and close the rest. */
272
for (i=0; fd_child_list[i].fd != -1; i++)
274
if (fd_child_list[i].dup_to != -1)
276
if (dup2 (fd_child_list[i].fd,
277
fd_child_list[i].dup_to) == -1)
280
/* FIXME: The debug file descriptor is not
281
dup'ed anyway, so we can't see this. */
282
TRACE_LOG1 ("dup2 failed in child: %s\n",
287
if (fd_child_list[i].dup_to == 0)
289
if (fd_child_list[i].dup_to == 2)
291
close (fd_child_list[i].fd);
295
if (!duped_stdin || !duped_stderr)
297
int fd = open ("/dev/null", O_RDWR);
301
/* FIXME: The debug file descriptor is not dup'ed
302
anyway, so we can't see this. */
303
TRACE_LOG1 ("can't open `/dev/null': %s\n",
308
/* Make sure that the process has a connected stdin. */
311
if (dup2 (fd, 0) == -1)
314
/* FIXME: The debug file descriptor is not dup'ed
315
anyway, so we can't see this. */
316
TRACE_LOG1 ("dup2(/dev/null, 0) failed: %s\n",
323
if (dup2 (fd, 2) == -1)
326
/* FIXME: The debug file descriptor is not dup'ed
327
anyway, so we can't see this. */
328
TRACE_LOG1 ("dup2(dev/null, 2) failed: %s\n",
336
execv ( path, argv );
337
/* Hmm: in that case we could write a special status code to the
340
/* FIXME: The debug file descriptor is not dup'ed anyway, so
341
we can't see this. */
342
TRACE_LOG1 ("exec of `%s' failed\n", path);
352
TRACE_LOG1 ("waiting for child process pid=%i", pid);
353
_gpgme_io_waitpid (pid, 1, &status, &signo);
355
return TRACE_SYSRES (-1);
357
/* .dup_to is not used in the parent list. */
358
for (i = 0; fd_parent_list[i].fd != -1; i++)
359
_gpgme_io_close (fd_parent_list[i].fd);
361
return TRACE_SYSRES (0);
365
/* Select on the list of fds. Returns: -1 = error, 0 = timeout or
366
nothing to select, > 0 = number of signaled fds. */
368
_gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
377
/* Use a 1s timeout. */
378
struct timeval timeout = { 1, 0 };
379
void *dbg_help = NULL;
380
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
381
"nfds=%u, nonblock=%u", nfds, nonblock);
389
TRACE_SEQ (dbg_help, "select on [ ");
392
for (i = 0; i < nfds; i++)
398
assert (!FD_ISSET (fds[i].fd, &readfds));
399
FD_SET (fds[i].fd, &readfds);
400
if (fds[i].fd > max_fd)
402
TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
405
else if (fds[i].for_write)
407
assert (!FD_ISSET (fds[i].fd, &writefds));
408
FD_SET (fds[i].fd, &writefds);
409
if (fds[i].fd > max_fd)
411
TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
416
TRACE_END (dbg_help, "]");
418
return TRACE_SYSRES (0);
422
count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
425
while (count < 0 && errno == EINTR);
427
return TRACE_SYSRES (-1);
429
TRACE_SEQ (dbg_help, "select OK [ ");
430
if (TRACE_ENABLED (dbg_help))
432
for (i = 0; i <= max_fd; i++)
434
if (FD_ISSET (i, &readfds))
435
TRACE_ADD1 (dbg_help, "r0x%x ", i);
436
if (FD_ISSET (i, &writefds))
437
TRACE_ADD1 (dbg_help, "w0x%x ", i);
439
TRACE_END (dbg_help, "]");
442
/* The variable N is used to optimize it a little bit. */
443
for (n = count, i = 0; i < nfds && n; i++)
447
else if (fds[i].for_read)
449
if (FD_ISSET (fds[i].fd, &readfds))
455
else if (fds[i].for_write)
457
if (FD_ISSET (fds[i].fd, &writefds))
464
return TRACE_SYSRES (count);
469
_gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
474
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
475
"msg=%p, flags=%i", msg, flags);
479
while (iov < msg->msg_iov + msg->msg_iovlen)
481
nread += iov->iov_len;
485
TRACE_LOG1 ("about to receive %d bytes", nread);
489
nread = _gpgme_ath_recvmsg (fd, msg, flags);
491
while (nread == -1 && errno == EINTR);
500
int len = nr > iov->iov_len ? iov->iov_len : nr;
501
TRACE_LOGBUF (msg->msg_iov->iov_base, len);
507
return TRACE_SYSRES (nread);
512
_gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
516
TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
517
"msg=%p, flags=%i", msg, flags);
521
while (iov < msg->msg_iov + msg->msg_iovlen)
523
nwritten += iov->iov_len;
527
TRACE_LOG1 ("about to receive %d bytes", nwritten);
531
int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
532
TRACE_LOGBUF (msg->msg_iov->iov_base, len);
539
nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
541
while (nwritten == -1 && errno == EINTR);
542
return TRACE_SYSRES (nwritten);
547
_gpgme_io_dup (int fd)