1 /* posix-io.c - Posix I/O functions
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2004, 2005, 2007, 2010 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, see <http://www.gnu.org/licenses/>.
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
37 #ifdef HAVE_SYS_TYPES_H
38 # include <sys/types.h>
45 #include <sys/resource.h>
55 _gpgme_io_subsystem_init (void)
59 sigaction (SIGPIPE, NULL, &act);
60 if (act.sa_handler == SIG_DFL)
62 act.sa_handler = SIG_IGN;
63 sigemptyset (&act.sa_mask);
65 sigaction (SIGPIPE, &act, NULL);
70 /* Write the printable version of FD to the buffer BUF of length
71 BUFLEN. The printable version is the representation on the command
72 line that the child process expects. */
74 _gpgme_io_fd2str (char *buf, int buflen, int fd)
76 return snprintf (buf, buflen, "%d", fd);
80 /* The table to hold notification handlers. We use a linear search
81 and extend the table as needed. */
82 struct notify_table_item_s
84 int fd; /* -1 indicates an unused entry. */
85 _gpgme_close_notify_handler_t handler;
88 typedef struct notify_table_item_s *notify_table_item_t;
90 static notify_table_item_t notify_table;
91 static size_t notify_table_size;
92 DEFINE_STATIC_LOCK (notify_table_lock);
97 _gpgme_io_read (int fd, void *buffer, size_t count)
100 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
101 "buffer=%p, count=%u", buffer, count);
105 nread = _gpgme_ath_read (fd, buffer, count);
107 while (nread == -1 && errno == EINTR);
109 TRACE_LOGBUF (buffer, nread);
110 return TRACE_SYSRES (nread);
115 _gpgme_io_write (int fd, const void *buffer, size_t count)
118 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
119 "buffer=%p, count=%u", buffer, count);
120 TRACE_LOGBUF (buffer, count);
124 nwritten = _gpgme_ath_write (fd, buffer, count);
126 while (nwritten == -1 && errno == EINTR);
128 return TRACE_SYSRES (nwritten);
133 _gpgme_io_pipe (int filedes[2], int inherit_idx)
137 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
138 "inherit_idx=%i (GPGME uses it for %s)",
139 inherit_idx, inherit_idx ? "reading" : "writing");
141 err = pipe (filedes);
143 return TRACE_SYSRES (err);
145 /* FIXME: Should get the old flags first. */
146 err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
155 return TRACE_SYSRES (err);
157 return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
162 _gpgme_io_close (int fd)
165 _gpgme_close_notify_handler_t handler = NULL;
169 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
174 return TRACE_SYSRES (-1);
177 /* First call the notify handler. */
178 LOCK (notify_table_lock);
179 for (idx=0; idx < notify_table_size; idx++)
181 if (notify_table[idx].fd == fd)
183 handler = notify_table[idx].handler;
184 handler_value = notify_table[idx].value;
185 notify_table[idx].handler = NULL;
186 notify_table[idx].value = NULL;
187 notify_table[idx].fd = -1; /* Mark slot as free. */
191 UNLOCK (notify_table_lock);
194 TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
195 handler (fd, handler_value);
198 /* Then do the close. */
200 return TRACE_SYSRES (res);
205 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
211 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
212 "close_handler=%p/%p", handler, value);
216 LOCK (notify_table_lock);
217 for (idx=0; idx < notify_table_size; idx++)
218 if (notify_table[idx].fd == -1)
220 if (idx == notify_table_size)
222 /* We need to increase the size of the table. The approach we
223 take is straightforward to minimize the risk of bugs. */
224 notify_table_item_t newtbl;
225 size_t newsize = notify_table_size + 64;
227 newtbl = calloc (newsize, sizeof *newtbl);
233 for (idx=0; idx < notify_table_size; idx++)
234 newtbl[idx] = notify_table[idx];
235 for (; idx < newsize; idx++)
238 newtbl[idx].handler = NULL;
239 newtbl[idx].value = NULL;
242 notify_table = newtbl;
243 idx = notify_table_size;
244 notify_table_size = newsize;
246 notify_table[idx].fd = fd;
247 notify_table[idx].handler = handler;
248 notify_table[idx].value = value;
251 UNLOCK (notify_table_lock);
253 return TRACE_SYSRES (res);
258 _gpgme_io_set_nonblocking (int fd)
262 TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
264 flags = fcntl (fd, F_GETFL, 0);
266 return TRACE_SYSRES (-1);
268 res = fcntl (fd, F_SETFL, flags);
269 return TRACE_SYSRES (res);
283 rc = getrlimit (RLIMIT_NOFILE, &rl);
286 source = "RLIMIT_NOFILE";
295 rc = getrlimit (RLIMIT_OFILE, &rl);
298 source = "RLIMIT_OFILE";
307 scres = sysconf (_SC_OPEN_MAX);
310 source = "_SC_OPEN_MAX";
323 #if !defined(RLIMIT_NOFILE) && !defined(RLIMIT_OFILE) \
324 && !defined(_SC_OPEN_MAX) && !defined(OPEN_MAX)
325 #warning "No known way to get the maximum number of file descriptors."
329 source = "arbitrary";
330 /* Arbitrary limit. */
334 TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
340 _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
346 if (_gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG) == pid)
348 if (WIFSIGNALED (status))
350 *r_status = 4; /* Need some value here. */
351 *r_signal = WTERMSIG (status);
353 else if (WIFEXITED (status))
354 *r_status = WEXITSTATUS (status);
356 *r_status = 4; /* Oops. */
363 /* Returns 0 on success, -1 on error. */
365 _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
366 struct spawn_fd_item_s *fd_list,
367 void (*atfork) (void *opaque, int reserved),
368 void *atforkvalue, pid_t *r_pid)
377 TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
382 TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
385 for (i = 0; fd_list[i].fd != -1; i++)
386 if (fd_list[i].dup_to == -1)
387 TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
389 TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
393 return TRACE_SYSRES (-1);
397 /* Intermediate child to prevent zombie processes. */
398 if ((pid = fork ()) == 0)
400 int max_fds = get_max_fds ();
408 atfork (atforkvalue, 0);
410 /* First close all fds which will not be inherited. */
411 for (fd = 0; fd < max_fds; fd++)
413 for (i = 0; fd_list[i].fd != -1; i++)
414 if (fd_list[i].fd == fd)
416 if (fd_list[i].fd == -1)
420 /* And now dup and close those to be duplicated. */
421 for (i = 0; fd_list[i].fd != -1; i++)
426 if (fd_list[i].dup_to != -1)
427 child_fd = fd_list[i].dup_to;
429 child_fd = fd_list[i].fd;
433 else if (child_fd == 2)
436 if (fd_list[i].dup_to == -1)
439 res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
443 /* FIXME: The debug file descriptor is not
444 dup'ed anyway, so we can't see this. */
445 TRACE_LOG1 ("dup2 failed in child: %s\n",
451 close (fd_list[i].fd);
454 if (! seen_stdin || ! seen_stderr)
456 fd = open ("/dev/null", O_RDWR);
460 /* FIXME: The debug file descriptor is not dup'ed
461 anyway, so we can't see this. */
462 TRACE_LOG1 ("can't open `/dev/null': %s\n",
467 /* Make sure that the process has a connected stdin. */
468 if (! seen_stdin && fd != 0)
470 if (dup2 (fd, 0) == -1)
473 /* FIXME: The debug file descriptor is not dup'ed
474 anyway, so we can't see this. */
475 TRACE_LOG1 ("dup2(/dev/null, 0) failed: %s\n",
481 if (! seen_stderr && fd != 2)
482 if (dup2 (fd, 2) == -1)
485 /* FIXME: The debug file descriptor is not dup'ed
486 anyway, so we can't see this. */
487 TRACE_LOG1 ("dup2(dev/null, 2) failed: %s\n",
492 if (fd != 0 && fd != 2)
496 execv (path, (char *const *) argv);
497 /* Hmm: in that case we could write a special status code to the
500 /* FIXME: The debug file descriptor is not dup'ed anyway, so
501 we can't see this. */
502 TRACE_LOG1 ("exec of `%s' failed\n", path);
513 TRACE_LOG1 ("waiting for child process pid=%i", pid);
514 _gpgme_io_waitpid (pid, 1, &status, &signo);
516 return TRACE_SYSRES (-1);
518 for (i = 0; fd_list[i].fd != -1; i++)
520 if (! (flags & IOSPAWN_FLAG_NOCLOSE))
521 _gpgme_io_close (fd_list[i].fd);
522 /* No handle translation. */
523 fd_list[i].peer_name = fd_list[i].fd;
529 return TRACE_SYSRES (0);
533 /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
534 nothing to select, > 0 = number of signaled fds. */
536 _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
545 /* Use a 1s timeout. */
546 struct timeval timeout = { 1, 0 };
547 void *dbg_help = NULL;
548 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
549 "nfds=%u, nonblock=%u", nfds, nonblock);
557 TRACE_SEQ (dbg_help, "select on [ ");
560 for (i = 0; i < nfds; i++)
566 assert (!FD_ISSET (fds[i].fd, &readfds));
567 FD_SET (fds[i].fd, &readfds);
568 if (fds[i].fd > max_fd)
570 TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
573 else if (fds[i].for_write)
575 assert (!FD_ISSET (fds[i].fd, &writefds));
576 FD_SET (fds[i].fd, &writefds);
577 if (fds[i].fd > max_fd)
579 TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
584 TRACE_END (dbg_help, "]");
586 return TRACE_SYSRES (0);
590 count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
593 while (count < 0 && errno == EINTR);
595 return TRACE_SYSRES (-1);
597 TRACE_SEQ (dbg_help, "select OK [ ");
598 if (TRACE_ENABLED (dbg_help))
600 for (i = 0; i <= max_fd; i++)
602 if (FD_ISSET (i, &readfds))
603 TRACE_ADD1 (dbg_help, "r0x%x ", i);
604 if (FD_ISSET (i, &writefds))
605 TRACE_ADD1 (dbg_help, "w0x%x ", i);
607 TRACE_END (dbg_help, "]");
610 /* The variable N is used to optimize it a little bit. */
611 for (n = count, i = 0; i < nfds && n; i++)
615 else if (fds[i].for_read)
617 if (FD_ISSET (fds[i].fd, &readfds))
623 else if (fds[i].for_write)
625 if (FD_ISSET (fds[i].fd, &writefds))
632 return TRACE_SYSRES (count);
637 _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
642 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
643 "msg=%p, flags=%i", msg, flags);
647 while (iov < msg->msg_iov + msg->msg_iovlen)
649 nread += iov->iov_len;
653 TRACE_LOG1 ("about to receive %d bytes", nread);
657 nread = _gpgme_ath_recvmsg (fd, msg, flags);
659 while (nread == -1 && errno == EINTR);
668 int len = nr > iov->iov_len ? iov->iov_len : nr;
669 TRACE_LOGBUF (msg->msg_iov->iov_base, len);
675 return TRACE_SYSRES (nread);
680 _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
684 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
685 "msg=%p, flags=%i", msg, flags);
689 while (iov < msg->msg_iov + msg->msg_iovlen)
691 nwritten += iov->iov_len;
695 TRACE_LOG1 ("about to receive %d bytes", nwritten);
699 int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
700 TRACE_LOGBUF (msg->msg_iov->iov_base, len);
707 nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
709 while (nwritten == -1 && errno == EINTR);
710 return TRACE_SYSRES (nwritten);
715 _gpgme_io_dup (int fd)
717 int new_fd = dup (fd);
719 TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
726 _gpgme_io_socket (int domain, int type, int proto)
730 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
731 "type=%i, proto=%i", type, proto);
733 res = socket (domain, type, proto);
735 return TRACE_SYSRES (res);
740 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
744 TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
745 "addr=%p, addrlen=%i", addr, addrlen);
747 res = ath_connect (fd, addr, addrlen);
749 return TRACE_SYSRES (res);