1 /* posix-io.c - Posix I/O functions
2 * Copyright (C) 2000 Werner Koch (dd9jn)
3 * Copyright (C) 2001, 2002 g10 Code GmbH
5 * This file is part of GPGME.
7 * GPGME is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * GPGME is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
34 #include <sys/types.h>
42 void (*handler) (int,void*);
47 _gpgme_io_read (int fd, void *buffer, size_t count)
51 DEBUG2 ("fd %d: about to read %d bytes\n", fd, (int) count);
54 nread = read (fd, buffer, count);
56 while (nread == -1 && errno == EINTR );
57 DEBUG2 ("fd %d: got %d bytes\n", fd, nread);
59 _gpgme_debug (2, "fd %d: got `%.*s'\n", fd, nread, buffer);
65 _gpgme_io_write (int fd, const void *buffer, size_t count)
69 DEBUG2 ("fd %d: about to write %d bytes\n", fd, (int) count);
70 _gpgme_debug (2, "fd %d: write `%.*s'\n", fd, (int) count, buffer);
73 nwritten = write (fd, buffer, count);
75 while (nwritten == -1 && errno == EINTR);
76 DEBUG2 ("fd %d: wrote %d bytes\n", fd, (int) nwritten);
81 _gpgme_io_pipe (int filedes[2], int inherit_idx)
88 /* FIXME: Should get the old flags first. */
89 err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
100 _gpgme_io_close (int fd)
104 /* First call the notify handler. */
105 DEBUG1 ("closing fd %d", fd);
106 if (fd >= 0 && fd < DIM (notify_table))
108 if (notify_table[fd].handler)
110 notify_table[fd].handler (fd, notify_table[fd].value);
111 notify_table[fd].handler = NULL;
112 notify_table[fd].value = NULL;
115 /* Then do the close. */
121 _gpgme_io_set_close_notify (int fd, void (*handler)(int, void*), void *value)
125 if (fd < 0 || fd >= DIM (notify_table))
127 DEBUG1 ("set notification for fd %d", fd);
128 notify_table[fd].handler = handler;
129 notify_table[fd].value = value;
135 _gpgme_io_set_nonblocking (int fd)
139 flags = fcntl (fd, F_GETFL, 0);
143 return fcntl (fd, F_SETFL, flags);
148 _gpgme_io_spawn (const char *path, char **argv,
149 struct spawn_fd_item_s *fd_child_list,
150 struct spawn_fd_item_s *fd_parent_list)
152 static volatile int fixed_signals;
158 struct sigaction act;
160 sigaction (SIGPIPE, NULL, &act);
161 if (act.sa_handler == SIG_DFL)
163 act.sa_handler = SIG_IGN;
164 sigemptyset (&act.sa_mask);
166 sigaction (SIGPIPE, &act, NULL);
169 /* XXX: This is not really MT safe. */
180 int duped_stderr = 0;
182 /* First close all fds which will not be duped. */
183 for (i=0; fd_child_list[i].fd != -1; i++)
184 if (fd_child_list[i].dup_to == -1)
185 close (fd_child_list[i].fd);
187 /* And now dup and close the rest. */
188 for (i=0; fd_child_list[i].fd != -1; i++)
190 if (fd_child_list[i].dup_to != -1)
192 if (dup2 (fd_child_list[i].fd,
193 fd_child_list[i].dup_to) == -1)
195 DEBUG1 ("dup2 failed in child: %s\n", strerror (errno));
198 if (fd_child_list[i].dup_to == 0)
200 if (fd_child_list[i].dup_to == 2)
202 close (fd_child_list[i].fd);
206 if (!duped_stdin || !duped_stderr)
208 int fd = open ("/dev/null", O_RDWR);
211 DEBUG1 ("can't open `/dev/null': %s\n", strerror (errno));
214 /* Make sure that the process has a connected stdin. */
217 if (dup2 (fd, 0) == -1)
219 DEBUG1("dup2(/dev/null, 0) failed: %s\n",
225 if (dup2 (fd, 2) == -1)
227 DEBUG1 ("dup2(dev/null, 2) failed: %s\n", strerror (errno));
233 execv ( path, argv );
234 /* Hmm: in that case we could write a special status code to the
236 DEBUG1 ("exec of `%s' failed\n", path);
240 /* .dup_to is not used in the parent list. */
241 for (i=0; fd_parent_list[i].fd != -1; i++)
242 close (fd_parent_list[i].fd);
249 _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
255 if (waitpid (pid, &status, hang? 0 : WNOHANG) == pid)
257 if (WIFSIGNALED (status))
259 *r_status = 4; /* Need some value here. */
260 *r_signal = WTERMSIG (status);
262 else if (WIFEXITED (status))
263 *r_status = WEXITSTATUS (status);
265 *r_status = 4; /* Oops. */
273 _gpgme_io_kill (int pid, int hard)
275 return kill (pid, hard ? SIGKILL : SIGTERM);
280 * Select on the list of fds.
281 * Returns: -1 = error
282 * 0 = timeout or nothing to select
283 * >0 = number of signaled fds
286 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds)
288 static fd_set readfds;
289 static fd_set writefds;
290 int any, i, max_fd, n, count;
291 struct timeval timeout = { 1, 0 }; /* Use a 1s timeout. */
292 void *dbg_help = NULL;
298 if (_gpgme_debug_level () > 2)
299 DEBUG_BEGIN (dbg_help, "gpgme:select on [ ");
301 for (i = 0; i < nfds; i++)
306 DEBUG_ADD1 (dbg_help, "f%d ", fds[i].fd );
307 else if (fds[i].for_read)
309 assert (!FD_ISSET (fds[i].fd, &readfds));
310 FD_SET (fds[i].fd, &readfds);
311 if (fds[i].fd > max_fd)
313 DEBUG_ADD1 (dbg_help, "r%d ", fds[i].fd);
316 else if (fds[i].for_write)
318 assert (!FD_ISSET ( fds[i].fd, &writefds));
319 FD_SET (fds[i].fd, &writefds);
320 if (fds[i].fd > max_fd)
322 DEBUG_ADD1 (dbg_help, "w%d ", fds[i].fd);
327 DEBUG_END (dbg_help, "]");
333 count = select (max_fd + 1, &readfds, &writefds, NULL, &timeout);
335 while (count < 0 && errno == EINTR);
338 DEBUG1 ("_gpgme_io_select failed: %s\n", strerror (errno));
339 return -1; /* error */
342 if (_gpgme_debug_level () > 2)
343 DEBUG_BEGIN (dbg_help, "select OK [ ");
344 if (DEBUG_ENABLED(dbg_help))
346 for (i = 0; i <= max_fd; i++)
348 if (FD_ISSET (i, &readfds))
349 DEBUG_ADD1 (dbg_help, "r%d ", i);
350 if (FD_ISSET (i, &writefds))
351 DEBUG_ADD1 (dbg_help, "w%d ", i);
353 DEBUG_END (dbg_help, "]");
356 /* n is used to optimize it a little bit. */
357 for (n = count, i = 0; i < nfds && n; i++)
361 else if (fds[i].for_read)
363 if (FD_ISSET (fds[i].fd, &readfds))
369 else if (fds[i].for_write)
371 if (FD_ISSET (fds[i].fd, &writefds))