LCOV - code coverage report
Current view: top level - src - posix-io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 257 311 82.6 %
Date: 2015-11-05 17:14:26 Functions: 15 17 88.2 %

          Line data    Source code
       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
       4             : 
       5             :    This file is part of GPGME.
       6             : 
       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.
      11             : 
      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.
      16             : 
      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/>.
      19             :  */
      20             : 
      21             : #ifdef HAVE_CONFIG_H
      22             : #include <config.h>
      23             : #endif
      24             : #include <stdio.h>
      25             : #include <stdlib.h>
      26             : #include <string.h>
      27             : #include <assert.h>
      28             : #include <errno.h>
      29             : #include <signal.h>
      30             : #include <fcntl.h>
      31             : #ifdef HAVE_UNISTD_H
      32             : # include <unistd.h>
      33             : #endif
      34             : #ifdef HAVE_SYS_TIME_H
      35             : # include <sys/time.h>
      36             : #endif
      37             : #ifdef HAVE_SYS_TYPES_H
      38             : # include <sys/types.h>
      39             : #endif
      40             : #include <sys/wait.h>
      41             : #ifdef HAVE_SYS_UIO_H
      42             : # include <sys/uio.h>
      43             : #endif
      44             : #include <ctype.h>
      45             : #include <sys/resource.h>
      46             : 
      47             : #include "util.h"
      48             : #include "priv-io.h"
      49             : #include "sema.h"
      50             : #include "ath.h"
      51             : #include "debug.h"
      52             : 
      53             : 
      54             : void
      55          29 : _gpgme_io_subsystem_init (void)
      56             : {
      57             :   struct sigaction act;
      58             : 
      59          29 :   sigaction (SIGPIPE, NULL, &act);
      60          29 :   if (act.sa_handler == SIG_DFL)
      61             :     {
      62          29 :       act.sa_handler = SIG_IGN;
      63          29 :       sigemptyset (&act.sa_mask);
      64          29 :       act.sa_flags = 0;
      65          29 :       sigaction (SIGPIPE, &act, NULL);
      66             :     }
      67          29 : }
      68             : 
      69             : 
      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.  */
      73             : int
      74         226 : _gpgme_io_fd2str (char *buf, int buflen, int fd)
      75             : {
      76         226 :   return snprintf (buf, buflen, "%d", fd);
      77             : }
      78             : 
      79             : 
      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
      83             : {
      84             :   int fd;  /* -1 indicates an unused entry.  */
      85             :   _gpgme_close_notify_handler_t handler;
      86             :   void *value;
      87             : };
      88             : typedef struct notify_table_item_s *notify_table_item_t;
      89             : 
      90             : static notify_table_item_t notify_table;
      91             : static size_t notify_table_size;
      92             : DEFINE_STATIC_LOCK (notify_table_lock);
      93             : 
      94             : 
      95             : 
      96             : int
      97        1005 : _gpgme_io_read (int fd, void *buffer, size_t count)
      98             : {
      99             :   int nread;
     100        1005 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
     101             :               "buffer=%p, count=%u", buffer, count);
     102             : 
     103             :   do
     104             :     {
     105        1005 :       nread = _gpgme_ath_read (fd, buffer, count);
     106             :     }
     107        1005 :   while (nread == -1 && errno == EINTR);
     108             : 
     109        1005 :   TRACE_LOGBUF (buffer, nread);
     110        1005 :   return TRACE_SYSRES (nread);
     111             : }
     112             : 
     113             : 
     114             : int
     115         115 : _gpgme_io_write (int fd, const void *buffer, size_t count)
     116             : {
     117             :   int nwritten;
     118         115 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
     119             :               "buffer=%p, count=%u", buffer, count);
     120         115 :   TRACE_LOGBUF (buffer, count);
     121             : 
     122             :   do
     123             :     {
     124         115 :       nwritten = _gpgme_ath_write (fd, buffer, count);
     125             :     }
     126         115 :   while (nwritten == -1 && errno == EINTR);
     127             : 
     128         115 :   return TRACE_SYSRES (nwritten);
     129             : }
     130             : 
     131             : 
     132             : int
     133         556 : _gpgme_io_pipe (int filedes[2], int inherit_idx)
     134             : {
     135             :   int saved_errno;
     136             :   int err;
     137         556 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
     138             :               "inherit_idx=%i (GPGME uses it for %s)",
     139             :               inherit_idx, inherit_idx ? "reading" : "writing");
     140             : 
     141         556 :   err = pipe (filedes);
     142         556 :   if (err < 0)
     143           0 :     return TRACE_SYSRES (err);
     144             : 
     145             :   /* FIXME: Should get the old flags first.  */
     146         556 :   err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
     147         556 :   saved_errno = errno;
     148         556 :   if (err < 0)
     149             :     {
     150           0 :       close (filedes[0]);
     151           0 :       close (filedes[1]);
     152             :     }
     153         556 :   errno = saved_errno;
     154         556 :   if (err)
     155           0 :     return TRACE_SYSRES (err);
     156             : 
     157         556 :   return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
     158             : }
     159             : 
     160             : 
     161             : int
     162        1141 : _gpgme_io_close (int fd)
     163             : {
     164             :   int res;
     165        1141 :   _gpgme_close_notify_handler_t handler = NULL;
     166             :   void *handler_value;
     167             :   int idx;
     168             : 
     169        1141 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
     170             : 
     171        1141 :   if (fd == -1)
     172             :     {
     173           0 :       errno = EINVAL;
     174           0 :       return TRACE_SYSRES (-1);
     175             :     }
     176             : 
     177             :   /* First call the notify handler.  */
     178        1141 :   LOCK (notify_table_lock);
     179       10965 :   for (idx=0; idx < notify_table_size; idx++)
     180             :     {
     181       10547 :       if (notify_table[idx].fd == fd)
     182             :         {
     183         723 :           handler       = notify_table[idx].handler;
     184         723 :           handler_value = notify_table[idx].value;
     185         723 :           notify_table[idx].handler = NULL;
     186         723 :           notify_table[idx].value = NULL;
     187         723 :           notify_table[idx].fd = -1; /* Mark slot as free.  */
     188         723 :           break;
     189             :         }
     190             :     }
     191        1141 :   UNLOCK (notify_table_lock);
     192        1141 :   if (handler)
     193             :     {
     194         723 :       TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
     195         723 :       handler (fd, handler_value);
     196             :     }
     197             : 
     198             :   /* Then do the close.  */
     199        1141 :   res = close (fd);
     200        1141 :   return TRACE_SYSRES (res);
     201             : }
     202             : 
     203             : 
     204             : int
     205         724 : _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
     206             :                             void *value)
     207             : {
     208         724 :   int res = 0;
     209             :   int idx;
     210             : 
     211         724 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
     212             :               "close_handler=%p/%p", handler, value);
     213             : 
     214         724 :   assert (fd != -1);
     215             : 
     216         724 :   LOCK (notify_table_lock);
     217        2916 :   for (idx=0; idx < notify_table_size; idx++)
     218        2889 :     if (notify_table[idx].fd == -1)
     219         697 :       break;
     220         724 :   if (idx == notify_table_size)
     221             :     {
     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          27 :       size_t newsize = notify_table_size + 64;
     226             : 
     227          27 :       newtbl = calloc (newsize, sizeof *newtbl);
     228          27 :       if (!newtbl)
     229             :         {
     230           0 :           res = -1;
     231           0 :           goto leave;
     232             :         }
     233          27 :       for (idx=0; idx < notify_table_size; idx++)
     234           0 :         newtbl[idx] = notify_table[idx];
     235        1755 :       for (; idx < newsize; idx++)
     236             :         {
     237        1728 :           newtbl[idx].fd = -1;
     238        1728 :           newtbl[idx].handler = NULL;
     239        1728 :           newtbl[idx].value = NULL;
     240             :         }
     241          27 :       free (notify_table);
     242          27 :       notify_table = newtbl;
     243          27 :       idx = notify_table_size;
     244          27 :       notify_table_size = newsize;
     245             :     }
     246         724 :   notify_table[idx].fd = fd;
     247         724 :   notify_table[idx].handler = handler;
     248         724 :   notify_table[idx].value = value;
     249             : 
     250             :  leave:
     251         724 :   UNLOCK (notify_table_lock);
     252             : 
     253         724 :   return TRACE_SYSRES (res);
     254             : }
     255             : 
     256             : 
     257             : int
     258          84 : _gpgme_io_set_nonblocking (int fd)
     259             : {
     260             :   int flags;
     261             :   int res;
     262          84 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
     263             : 
     264          84 :   flags = fcntl (fd, F_GETFL, 0);
     265          84 :   if (flags == -1)
     266           0 :     return TRACE_SYSRES (-1);
     267          84 :   flags |= O_NONBLOCK;
     268          84 :   res = fcntl (fd, F_SETFL, flags);
     269          84 :   return TRACE_SYSRES (res);
     270             : }
     271             : 
     272             : 
     273             : static long int
     274         325 : get_max_fds (void)
     275             : {
     276         325 :   char *source = NULL;
     277         325 :   long int fds = -1;
     278             :   int rc;
     279             : 
     280             : #ifdef RLIMIT_NOFILE
     281             :   {
     282             :     struct rlimit rl;
     283         325 :     rc = getrlimit (RLIMIT_NOFILE, &rl);
     284         325 :     if (rc == 0)
     285             :       {
     286         325 :         source = "RLIMIT_NOFILE";
     287         325 :         fds = rl.rlim_max;
     288             :       }
     289             :   }
     290             : #endif
     291             : #ifdef RLIMIT_OFILE
     292         325 :   if (fds == -1)
     293             :     {
     294             :       struct rlimit rl;
     295           0 :       rc = getrlimit (RLIMIT_OFILE, &rl);
     296           0 :       if (rc == 0)
     297             :         {
     298           0 :           source = "RLIMIT_OFILE";
     299           0 :           fds = rl.rlim_max;
     300             :         }
     301             :     }
     302             : #endif
     303             : #ifdef _SC_OPEN_MAX
     304         325 :   if (fds == -1)
     305             :     {
     306             :       long int scres;
     307           0 :       scres = sysconf (_SC_OPEN_MAX);
     308           0 :       if (scres >= 0)
     309             :         {
     310           0 :           source = "_SC_OPEN_MAX";
     311           0 :           return scres;
     312             :         }
     313             :     }
     314             : #endif
     315             : #ifdef OPEN_MAX
     316             :   if (fds == -1)
     317             :     {
     318             :       source = "OPEN_MAX";
     319             :       fds = OPEN_MAX;
     320             :     }
     321             : #endif
     322             : 
     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."
     326             : #endif
     327         325 :   if (fds == -1)
     328             :     {
     329           0 :       source = "arbitrary";
     330             :       /* Arbitrary limit.  */
     331           0 :       fds = 1024;
     332             :     }
     333             : 
     334         325 :   TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
     335         325 :   return fds;
     336             : }
     337             : 
     338             : 
     339             : int
     340         325 : _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
     341             : {
     342             :   int status;
     343             :   pid_t ret;
     344             : 
     345         325 :   *r_status = 0;
     346         325 :   *r_signal = 0;
     347             :   do
     348         325 :     ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
     349         324 :   while (ret == (pid_t)(-1) && errno == EINTR);
     350             : 
     351         324 :   if (ret == pid)
     352             :     {
     353         324 :       if (WIFSIGNALED (status))
     354             :         {
     355           0 :           *r_status = 4; /* Need some value here.  */
     356           0 :           *r_signal = WTERMSIG (status);
     357             :         }
     358         324 :       else if (WIFEXITED (status))
     359         324 :         *r_status = WEXITSTATUS (status);
     360             :       else
     361           0 :         *r_status = 4; /* Oops.  */
     362         324 :       return 1;
     363             :     }
     364           0 :   return 0;
     365             : }
     366             : 
     367             : 
     368             : /* Returns 0 on success, -1 on error.  */
     369             : int
     370         324 : _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
     371             :                  struct spawn_fd_item_s *fd_list,
     372             :                  void (*atfork) (void *opaque, int reserved),
     373             :                  void *atforkvalue, pid_t *r_pid)
     374             : {
     375             :   pid_t pid;
     376             :   int i;
     377             :   int status;
     378             :   int signo;
     379             : 
     380         324 :   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
     381             :               "path=%s", path);
     382         324 :   i = 0;
     383        4381 :   while (argv[i])
     384             :     {
     385        3733 :       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
     386        3733 :       i++;
     387             :     }
     388         870 :   for (i = 0; fd_list[i].fd != -1; i++)
     389         546 :     if (fd_list[i].dup_to == -1)
     390         234 :       TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
     391             :     else
     392         312 :       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
     393             : 
     394         324 :   pid = fork ();
     395         650 :   if (pid == -1)
     396           0 :     return TRACE_SYSRES (-1);
     397             : 
     398         650 :   if (!pid)
     399             :     {
     400             :       /* Intermediate child to prevent zombie processes.  */
     401         325 :       if ((pid = fork ()) == 0)
     402             :         {
     403         325 :           int max_fds = get_max_fds ();
     404             :           int fd;
     405             : 
     406             :           /* Child.  */
     407         325 :           int seen_stdin = 0;
     408         325 :           int seen_stdout = 0;
     409         325 :           int seen_stderr = 0;
     410             : 
     411         325 :           if (atfork)
     412           8 :             atfork (atforkvalue, 0);
     413             : 
     414             :           /* First close all fds which will not be inherited.  */
     415    83200325 :           for (fd = 0; fd < max_fds; fd++)
     416             :             {
     417   223743094 :               for (i = 0; fd_list[i].fd != -1; i++)
     418   140543643 :                 if (fd_list[i].fd == fd)
     419         549 :                   break;
     420    83200000 :               if (fd_list[i].fd == -1)
     421    83199451 :                 close (fd);
     422             :             }
     423             : 
     424             :           /* And now dup and close those to be duplicated.  */
     425         874 :           for (i = 0; fd_list[i].fd != -1; i++)
     426             :             {
     427             :               int child_fd;
     428             :               int res;
     429             : 
     430         549 :               if (fd_list[i].dup_to != -1)
     431         313 :                 child_fd = fd_list[i].dup_to;
     432             :               else
     433         236 :                 child_fd = fd_list[i].fd;
     434             : 
     435         549 :               if (child_fd == 0)
     436           0 :                 seen_stdin = 1;
     437         549 :               else if (child_fd == 1)
     438         313 :                 seen_stdout = 1;
     439         236 :               else if (child_fd == 2)
     440           0 :                 seen_stderr = 1;
     441             : 
     442         549 :               if (fd_list[i].dup_to == -1)
     443         236 :                 continue;
     444             : 
     445         313 :               res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
     446         313 :               if (res < 0)
     447             :                 {
     448             : #if 0
     449             :                   /* FIXME: The debug file descriptor is not
     450             :                      dup'ed anyway, so we can't see this.  */
     451             :                   TRACE_LOG1 ("dup2 failed in child: %s\n",
     452             :                               strerror (errno));
     453             : #endif
     454           0 :                   _exit (8);
     455             :                 }
     456             : 
     457         313 :               close (fd_list[i].fd);
     458             :             }
     459             : 
     460         325 :           if (! seen_stdin || ! seen_stdout || !seen_stderr)
     461             :             {
     462         325 :               fd = open ("/dev/null", O_RDWR);
     463         325 :               if (fd == -1)
     464             :                 {
     465             :                   /* The debug file descriptor is not dup'ed, so we
     466             :                      can't do a trace output.  */
     467           0 :                   _exit (8);
     468             :                 }
     469             :               /* Make sure that the process has connected stdin.  */
     470         325 :               if (! seen_stdin && fd != 0)
     471             :                 {
     472           0 :                   if (dup2 (fd, 0) == -1)
     473           0 :                     _exit (8);
     474             :                 }
     475         325 :               if (! seen_stdout && fd != 1)
     476             :                 {
     477          12 :                   if (dup2 (fd, 1) == -1)
     478           0 :                     _exit (8);
     479             :                 }
     480         325 :               if (! seen_stderr && fd != 2)
     481             :                 {
     482         325 :                   if (dup2 (fd, 2) == -1)
     483           0 :                     _exit (8);
     484             :                 }
     485         325 :               if (fd != 0 && fd != 1 && fd != 2)
     486           0 :                 close (fd);
     487             :             }
     488             : 
     489         325 :           execv (path, (char *const *) argv);
     490             :           /* Hmm: in that case we could write a special status code to the
     491             :              status-pipe.  */
     492         325 :           _exit (8);
     493             :           /* End child.  */
     494             :         }
     495           0 :       if (pid == -1)
     496           0 :         _exit (1);
     497             :       else
     498           0 :         _exit (0);
     499             :     }
     500             : 
     501         325 :   TRACE_LOG1 ("waiting for child process pid=%i", pid);
     502         325 :   _gpgme_io_waitpid (pid, 1, &status, &signo);
     503         324 :   if (status)
     504           0 :     return TRACE_SYSRES (-1);
     505             : 
     506         869 :   for (i = 0; fd_list[i].fd != -1; i++)
     507             :     {
     508         545 :       if (! (flags & IOSPAWN_FLAG_NOCLOSE))
     509         537 :         _gpgme_io_close (fd_list[i].fd);
     510             :       /* No handle translation.  */
     511         545 :       fd_list[i].peer_name = fd_list[i].fd;
     512             :     }
     513             : 
     514         324 :   if (r_pid)
     515         132 :     *r_pid = pid;
     516             : 
     517         324 :   return TRACE_SYSRES (0);
     518             : }
     519             : 
     520             : 
     521             : /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
     522             :    nothing to select, > 0 = number of signaled fds.  */
     523             : int
     524        1826 : _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
     525             : {
     526             :   fd_set readfds;
     527             :   fd_set writefds;
     528             :   unsigned int i;
     529             :   int any;
     530             :   int max_fd;
     531             :   int n;
     532             :   int count;
     533             :   /* Use a 1s timeout.  */
     534        1826 :   struct timeval timeout = { 1, 0 };
     535        1826 :   void *dbg_help = NULL;
     536        1826 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
     537             :               "nfds=%u, nonblock=%u", nfds, nonblock);
     538             : 
     539        1826 :   FD_ZERO (&readfds);
     540        1826 :   FD_ZERO (&writefds);
     541        1826 :   max_fd = 0;
     542        1826 :   if (nonblock)
     543         970 :     timeout.tv_sec = 0;
     544             : 
     545        1826 :   TRACE_SEQ (dbg_help, "select on [ ");
     546             : 
     547        1826 :   any = 0;
     548       11356 :   for (i = 0; i < nfds; i++)
     549             :     {
     550        9530 :       if (fds[i].fd == -1)
     551        6827 :         continue;
     552        2703 :       if (fds[i].for_read)
     553             :         {
     554        2332 :           assert (!FD_ISSET (fds[i].fd, &readfds));
     555        2332 :           FD_SET (fds[i].fd, &readfds);
     556        2332 :           if (fds[i].fd > max_fd)
     557        2306 :             max_fd = fds[i].fd;
     558        2332 :           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
     559        2332 :           any = 1;
     560             :         }
     561         371 :       else if (fds[i].for_write)
     562             :         {
     563         371 :           assert (!FD_ISSET (fds[i].fd, &writefds));
     564         371 :           FD_SET (fds[i].fd, &writefds);
     565         371 :           if (fds[i].fd > max_fd)
     566         356 :             max_fd = fds[i].fd;
     567         371 :           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
     568         371 :           any = 1;
     569             :         }
     570        2703 :       fds[i].signaled = 0;
     571             :     }
     572        1826 :   TRACE_END (dbg_help, "]");
     573        1826 :   if (!any)
     574          51 :     return TRACE_SYSRES (0);
     575             : 
     576             :   do
     577             :     {
     578        1775 :       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
     579             :                                  &timeout);
     580             :     }
     581        1775 :   while (count < 0 && errno == EINTR);
     582        1775 :   if (count < 0)
     583           0 :     return TRACE_SYSRES (-1);
     584             : 
     585        1775 :   TRACE_SEQ (dbg_help, "select OK [ ");
     586        1775 :   if (TRACE_ENABLED (dbg_help))
     587             :     {
     588           0 :       for (i = 0; i <= max_fd; i++)
     589             :         {
     590           0 :           if (FD_ISSET (i, &readfds))
     591           0 :             TRACE_ADD1 (dbg_help, "r0x%x ", i);
     592           0 :           if (FD_ISSET (i, &writefds))
     593           0 :             TRACE_ADD1 (dbg_help, "w0x%x ", i);
     594             :         }
     595           0 :       TRACE_END (dbg_help, "]");
     596             :     }
     597             : 
     598             :   /* The variable N is used to optimize it a little bit.  */
     599        4176 :   for (n = count, i = 0; i < nfds && n; i++)
     600             :     {
     601        2401 :       if (fds[i].fd == -1)
     602             :         ;
     603        2369 :       else if (fds[i].for_read)
     604             :         {
     605        2001 :           if (FD_ISSET (fds[i].fd, &readfds))
     606             :             {
     607        1564 :               fds[i].signaled = 1;
     608        1564 :               n--;
     609             :             }
     610             :         }
     611         368 :       else if (fds[i].for_write)
     612             :         {
     613         368 :           if (FD_ISSET (fds[i].fd, &writefds))
     614             :             {
     615         368 :               fds[i].signaled = 1;
     616         368 :               n--;
     617             :             }
     618             :         }
     619             :     }
     620        1775 :   return TRACE_SYSRES (count);
     621             : }
     622             : 
     623             : 
     624             : int
     625         125 : _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
     626             : {
     627             :   int nread;
     628             :   int saved_errno;
     629             :   struct iovec *iov;
     630         125 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
     631             :               "msg=%p, flags=%i", msg, flags);
     632             : 
     633         125 :   nread = 0;
     634         125 :   iov = msg->msg_iov;
     635         375 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     636             :     {
     637         125 :       nread += iov->iov_len;
     638         125 :       iov++;
     639             :     }
     640             : 
     641         125 :   TRACE_LOG1 ("about to receive %d bytes", nread);
     642             : 
     643             :   do
     644             :     {
     645         125 :       nread = _gpgme_ath_recvmsg (fd, msg, flags);
     646             :     }
     647         125 :   while (nread == -1 && errno == EINTR);
     648         125 :   saved_errno = errno;
     649         125 :   if (nread > 0)
     650             :     {
     651         125 :       int nr = nread;
     652             : 
     653         125 :       iov = msg->msg_iov;
     654         375 :       while (nr > 0)
     655             :         {
     656         125 :           int len = nr > iov->iov_len ? iov->iov_len : nr;
     657         125 :           TRACE_LOGBUF (msg->msg_iov->iov_base, len);
     658         125 :           iov++;
     659         125 :           nr -= len;
     660             :         }
     661             :     }
     662         125 :   errno = saved_errno;
     663         125 :   return TRACE_SYSRES (nread);
     664             : }
     665             : 
     666             : 
     667             : int
     668         240 : _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
     669             : {
     670             :   int nwritten;
     671             :   struct iovec *iov;
     672         240 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
     673             :               "msg=%p, flags=%i", msg, flags);
     674             : 
     675         240 :   nwritten = 0;
     676         240 :   iov = msg->msg_iov;
     677         720 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     678             :     {
     679         240 :       nwritten += iov->iov_len;
     680         240 :       iov++;
     681             :     }
     682             : 
     683         240 :   TRACE_LOG1 ("about to receive %d bytes", nwritten);
     684         240 :   iov = msg->msg_iov;
     685         720 :   while (nwritten > 0)
     686             :     {
     687         240 :       int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
     688         240 :       TRACE_LOGBUF (msg->msg_iov->iov_base, len);
     689         240 :       iov++;
     690         240 :       nwritten -= len;
     691             :     }
     692             : 
     693             :   do
     694             :     {
     695         240 :       nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
     696             :     }
     697         240 :   while (nwritten == -1 && errno == EINTR);
     698         240 :   return TRACE_SYSRES (nwritten);
     699             : }
     700             : 
     701             : 
     702             : int
     703          14 : _gpgme_io_dup (int fd)
     704             : {
     705             :   int new_fd;
     706             : 
     707             :   do
     708          14 :     new_fd = dup (fd);
     709          14 :   while (new_fd == -1 && errno == EINTR);
     710             : 
     711          14 :   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
     712             : 
     713          14 :   return new_fd;
     714             : }
     715             : 
     716             : 
     717             : int
     718           0 : _gpgme_io_socket (int domain, int type, int proto)
     719             : {
     720             :   int res;
     721             : 
     722           0 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
     723             :               "type=%i, proto=%i", type, proto);
     724             : 
     725           0 :   res = socket (domain, type, proto);
     726             : 
     727           0 :   return TRACE_SYSRES (res);
     728             : }
     729             : 
     730             : 
     731             : int
     732           0 : _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
     733             : {
     734             :   int res;
     735             : 
     736           0 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
     737             :               "addr=%p, addrlen=%i", addr, addrlen);
     738             : 
     739             :   do
     740           0 :     res = ath_connect (fd, addr, addrlen);
     741           0 :   while (res == -1 && errno == EINTR);
     742             : 
     743           0 :   return TRACE_SYSRES (res);
     744             : }

Generated by: LCOV version 1.11