1 /* posix-io.c - Posix I/O functions
2 * Copyright (C) 2000 Werner Koch (dd9jn)
4 * This file is part of GPGME.
6 * GPGME is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GPGME is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
22 #ifndef HAVE_DOSISH_SYSTEM
30 #include <sys/types.h>
38 #define DEBUG_SELECT_ENABLED 0
40 #if DEBUG_SELECT_ENABLED
41 # define DEBUG_SELECT(a) fprintf a
43 # define DEBUG_SELECT(a) do { } while(0)
48 _gpgme_io_read ( int fd, void *buffer, size_t count )
53 nread = read (fd, buffer, count);
54 } while (nread == -1 && errno == EINTR );
60 _gpgme_io_write ( int fd, const void *buffer, size_t count )
65 nwritten = write (fd, buffer, count);
66 } while (nwritten == -1 && errno == EINTR );
71 _gpgme_io_pipe ( int filedes[2], int inherit_idx )
73 /* we don't need inherit_idx in this implementation */
74 return pipe ( filedes );
78 _gpgme_io_close ( int fd )
86 _gpgme_io_set_nonblocking ( int fd )
90 flags = fcntl (fd, F_GETFL, 0);
94 return fcntl (fd, F_SETFL, flags);
99 _gpgme_io_spawn ( const char *path, char **argv,
100 struct spawn_fd_item_s *fd_child_list,
101 struct spawn_fd_item_s *fd_parent_list )
103 static volatile int fixed_signals;
107 if ( !fixed_signals ) {
108 struct sigaction act;
110 sigaction( SIGPIPE, NULL, &act );
111 if( act.sa_handler == SIG_DFL ) {
112 act.sa_handler = SIG_IGN;
113 sigemptyset( &act.sa_mask );
115 sigaction( SIGPIPE, &act, NULL);
118 /* fixme: This is not really MT safe */
126 if ( !pid ) { /* child */
128 int duped_stderr = 0;
130 /* first close all fds which will not be duped */
131 for (i=0; fd_child_list[i].fd != -1; i++ ) {
132 if (fd_child_list[i].dup_to == -1 )
133 close (fd_child_list[i].fd);
135 /* and now dup and close the rest */
136 for (i=0; fd_child_list[i].fd != -1; i++ ) {
137 if (fd_child_list[i].dup_to != -1 ) {
138 if ( dup2 (fd_child_list[i].fd,
139 fd_child_list[i].dup_to ) == -1 ) {
140 fprintf (stderr, "dup2 failed in child: %s\n",
144 if ( fd_child_list[i].dup_to == 0 )
146 if ( fd_child_list[i].dup_to == 2 )
148 close (fd_child_list[i].fd);
152 if( !duped_stdin || !duped_stderr ) {
153 int fd = open ( "/dev/null", O_RDWR );
155 fprintf (stderr,"can't open `/dev/null': %s\n",
159 /* Make sure that the process has a connected stdin */
160 if ( !duped_stdin ) {
161 if ( dup2 ( fd, 0 ) == -1 ) {
162 fprintf (stderr,"dup2(/dev/null, 0) failed: %s\n",
167 /* We normally don't want all the normal output */
168 if ( !duped_stderr ) {
169 if (!getenv ("GPGME_DEBUG") ) {
170 if ( dup2 ( fd, 2 ) == -1 ) {
171 fprintf (stderr,"dup2(dev/null, 2) failed: %s\n",
180 execv ( path, argv );
181 /* Hmm: in that case we could write a special status code to the
183 fprintf (stderr,"exec of `%s' failed\n", path );
187 /* .dup_to is not used in the parent list */
188 for (i=0; fd_parent_list[i].fd != -1; i++ ) {
189 close (fd_parent_list[i].fd);
197 _gpgme_io_waitpid ( int pid, int hang, int *r_status, int *r_signal )
203 if ( waitpid ( pid, &status, hang? 0 : WNOHANG ) == pid ) {
204 if ( WIFSIGNALED (status) ) {
205 *r_status = 4; /* Need some value here */
206 *r_signal = WTERMSIG (status);
208 else if ( WIFEXITED (status) ) {
209 *r_status = WEXITSTATUS (status);
212 *r_status = 4; /* oops */
221 * Select on the list of fds.
222 * Returns: -1 = error
223 * 0 = timeout or nothing to select
224 * >0 = number of signaled fds
227 _gpgme_io_select ( struct io_select_fd_s *fds, size_t nfds )
229 static fd_set readfds;
230 static fd_set writefds;
231 int any, i, max_fd, n, count;
232 struct timeval timeout = { 1, 0 }; /* Use a one second timeout */
234 FD_ZERO ( &readfds );
235 FD_ZERO ( &writefds );
238 DEBUG_SELECT ((stderr, "gpgme:select on [ "));
240 for ( i=0; i < nfds; i++ ) {
241 if ( fds[i].fd == -1 )
243 if ( fds[i].for_read ) {
244 assert ( !FD_ISSET ( fds[i].fd, &readfds ) );
245 FD_SET ( fds[i].fd, &readfds );
246 if ( fds[i].fd > max_fd )
248 DEBUG_SELECT ((stderr, "r%d ", fds[i].fd ));
251 else if ( fds[i].for_write ) {
252 assert ( !FD_ISSET ( fds[i].fd, &writefds ) );
253 FD_SET ( fds[i].fd, &writefds );
254 if ( fds[i].fd > max_fd )
256 DEBUG_SELECT ((stderr, "w%d ", fds[i].fd ));
261 DEBUG_SELECT ((stderr, "]\n" ));
266 count = select ( max_fd+1, &readfds, &writefds, NULL, &timeout );
267 } while ( count < 0 && errno == EINTR);
269 fprintf (stderr, "_gpgme_io_select failed: %s\n", strerror (errno) );
270 return -1; /* error */
273 #if DEBUG_SELECT_ENABLED
274 fprintf (stderr, "gpgme:select OK [ " );
275 for (i=0; i <= max_fd; i++ ) {
276 if (FD_ISSET (i, &readfds) )
277 fprintf (stderr, "r%d ", i );
278 if (FD_ISSET (i, &writefds) )
279 fprintf (stderr, "w%d ", i );
281 fprintf (stderr, "]\n" );
284 /* n is used to optimize it a little bit */
285 for ( n=count, i=0; i < nfds && n ; i++ ) {
286 if ( fds[i].fd == -1 )
288 else if ( fds[i].for_read ) {
289 if ( FD_ISSET ( fds[i].fd, &readfds ) ) {
294 else if ( fds[i].for_write ) {
295 if ( FD_ISSET ( fds[i].fd, &writefds ) ) {
305 #endif /*!HAVE_DOSISH_SYSTEM*/