1 /* posix-io.c - Posix I/O functions
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2004, 2005 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>
45 _gpgme_io_subsystem_init (void)
49 sigaction (SIGPIPE, NULL, &act);
50 if (act.sa_handler == SIG_DFL)
52 act.sa_handler = SIG_IGN;
53 sigemptyset (&act.sa_mask);
55 sigaction (SIGPIPE, &act, NULL);
60 /* Write the printable version of FD to the buffer BUF of length
61 BUFLEN. The printable version is the representation on the command
62 line that the child process expects. */
64 _gpgme_io_fd2str (char *buf, int buflen, int fd)
66 return snprintf (buf, buflen, "%d", fd);
72 void (*handler) (int,void*);
77 _gpgme_io_read (int fd, void *buffer, size_t count)
82 DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
85 nread = _gpgme_ath_read (fd, buffer, count);
87 while (nread == -1 && errno == EINTR);
89 DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
91 _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
98 _gpgme_io_write (int fd, const void *buffer, size_t count)
103 DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count);
104 _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
107 nwritten = _gpgme_ath_write (fd, buffer, count);
109 while (nwritten == -1 && errno == EINTR);
111 DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten);
118 _gpgme_io_pipe (int filedes[2], int inherit_idx)
123 err = pipe (filedes);
126 /* FIXME: Should get the old flags first. */
127 err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
140 _gpgme_io_close (int fd)
144 /* First call the notify handler. */
145 DEBUG1 ("closing fd %d", fd);
146 if (fd >= 0 && fd < (int) DIM (notify_table))
148 if (notify_table[fd].handler)
150 notify_table[fd].handler (fd, notify_table[fd].value);
151 notify_table[fd].handler = NULL;
152 notify_table[fd].value = NULL;
155 /* Then do the close. */
161 _gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
165 if (fd < 0 || fd >= (int) DIM (notify_table))
167 DEBUG1 ("set notification for fd %d", fd);
168 notify_table[fd].handler = handler;
169 notify_table[fd].value = value;
175 _gpgme_io_set_nonblocking (int fd)
179 flags = fcntl (fd, F_GETFL, 0);
183 return fcntl (fd, F_SETFL, flags);
188 _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
194 if (_gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG) == pid)
196 if (WIFSIGNALED (status))
198 *r_status = 4; /* Need some value here. */
199 *r_signal = WTERMSIG (status);
201 else if (WIFEXITED (status))
202 *r_status = WEXITSTATUS (status);
204 *r_status = 4; /* Oops. */
211 /* Returns 0 on success, -1 on error. */
213 _gpgme_io_spawn (const char *path, char **argv,
214 struct spawn_fd_item_s *fd_child_list,
215 struct spawn_fd_item_s *fd_parent_list)
227 /* Intermediate child to prevent zombie processes. */
228 if ((pid = fork ()) == 0)
232 int duped_stderr = 0;
234 /* First close all fds which will not be duped. */
235 for (i=0; fd_child_list[i].fd != -1; i++)
236 if (fd_child_list[i].dup_to == -1)
237 close (fd_child_list[i].fd);
239 /* And now dup and close the rest. */
240 for (i=0; fd_child_list[i].fd != -1; i++)
242 if (fd_child_list[i].dup_to != -1)
244 if (dup2 (fd_child_list[i].fd,
245 fd_child_list[i].dup_to) == -1)
247 DEBUG1 ("dup2 failed in child: %s\n", strerror (errno));
250 if (fd_child_list[i].dup_to == 0)
252 if (fd_child_list[i].dup_to == 2)
254 close (fd_child_list[i].fd);
258 if (!duped_stdin || !duped_stderr)
260 int fd = open ("/dev/null", O_RDWR);
263 DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno));
266 /* Make sure that the process has a connected stdin. */
269 if (dup2 (fd, 0) == -1)
271 DEBUG1("dup2(/dev/null, 0) failed: %s\n",
277 if (dup2 (fd, 2) == -1)
279 DEBUG1 ("dup2(dev/null, 2) failed: %s\n",
286 execv ( path, argv );
287 /* Hmm: in that case we could write a special status code to the
289 DEBUG1 ("exec of `%s' failed\n", path);
298 _gpgme_io_waitpid (pid, 1, &status, &signo);
302 /* .dup_to is not used in the parent list. */
303 for (i = 0; fd_parent_list[i].fd != -1; i++)
304 _gpgme_io_close (fd_parent_list[i].fd);
311 * Select on the list of fds.
312 * Returns: -1 = error
313 * 0 = timeout or nothing to select
314 * >0 = number of signaled fds
317 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
322 int any, max_fd, n, count;
323 struct timeval timeout = { 1, 0 }; /* Use a 1s timeout. */
324 void *dbg_help = NULL;
332 DEBUG_BEGIN (dbg_help, 3, "gpgme:select on [ ");
334 for (i = 0; i < nfds; i++)
339 DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd);
340 else if (fds[i].for_read)
342 assert (!FD_ISSET (fds[i].fd, &readfds));
343 FD_SET (fds[i].fd, &readfds);
344 if (fds[i].fd > max_fd)
346 DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd);
349 else if (fds[i].for_write)
351 assert (!FD_ISSET (fds[i].fd, &writefds));
352 FD_SET (fds[i].fd, &writefds);
353 if (fds[i].fd > max_fd)
355 DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd);
360 DEBUG_END (dbg_help, "]");
366 count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
369 while (count < 0 && errno == EINTR);
372 int saved_errno = errno;
373 DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno));
375 return -1; /* error */
378 DEBUG_BEGIN (dbg_help, 3, "select OK [ ");
379 if (DEBUG_ENABLED (dbg_help))
381 for (i = 0; i <= max_fd; i++)
383 if (FD_ISSET (i, &readfds))
384 DEBUG_ADD1 (dbg_help, "r%d ", i);
385 if (FD_ISSET (i, &writefds))
386 DEBUG_ADD1 (dbg_help, "w%d ", i);
388 DEBUG_END (dbg_help, "]");
391 /* n is used to optimize it a little bit. */
392 for (n = count, i = 0; i < nfds && n; i++)
396 else if (fds[i].for_read)
398 if (FD_ISSET (fds[i].fd, &readfds))
404 else if (fds[i].for_write)
406 if (FD_ISSET (fds[i].fd, &writefds))
418 _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
426 while (iov < msg->msg_iov + msg->msg_iovlen)
428 nread += iov->iov_len;
432 DEBUG2 ("fd %d: about to receive %d bytes\n",
436 nread = _gpgme_ath_recvmsg (fd, msg, flags);
438 while (nread == -1 && errno == EINTR);
440 DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
448 int len = nr > iov->iov_len ? iov->iov_len : nr;
449 _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, len,
450 msg->msg_iov->iov_base);
461 _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
469 while (iov < msg->msg_iov + msg->msg_iovlen)
471 nwritten += iov->iov_len;
475 DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) nwritten);
479 int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
480 _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, len,
481 msg->msg_iov->iov_base);
488 nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
490 while (nwritten == -1 && errno == EINTR);
492 DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten);
499 _gpgme_io_dup (int fd)