LCOV - code coverage report
Current view: top level - src - posix-io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 276 337 81.9 %
Date: 2016-11-29 15:07:43 Functions: 17 17 100.0 %

          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 <https://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             : #ifdef HAVE_STDINT_H
      27             : # include <stdint.h>
      28             : #endif
      29             : #include <string.h>
      30             : #include <assert.h>
      31             : #include <errno.h>
      32             : #include <signal.h>
      33             : #include <fcntl.h>
      34             : #ifdef HAVE_UNISTD_H
      35             : # include <unistd.h>
      36             : #endif
      37             : #ifdef HAVE_SYS_TIME_H
      38             : # include <sys/time.h>
      39             : #endif
      40             : #ifdef HAVE_SYS_TYPES_H
      41             : # include <sys/types.h>
      42             : #endif
      43             : #include <sys/wait.h>
      44             : #ifdef HAVE_SYS_UIO_H
      45             : # include <sys/uio.h>
      46             : #endif
      47             : #include <ctype.h>
      48             : #include <sys/resource.h>
      49             : 
      50             : #if __linux__
      51             : # include <sys/types.h>
      52             : # include <dirent.h>
      53             : #endif /*__linux__ */
      54             : 
      55             : 
      56             : #include "util.h"
      57             : #include "priv-io.h"
      58             : #include "sema.h"
      59             : #include "ath.h"
      60             : #include "debug.h"
      61             : 
      62             : 
      63             : void
      64          84 : _gpgme_io_subsystem_init (void)
      65             : {
      66             :   struct sigaction act;
      67             : 
      68          84 :   sigaction (SIGPIPE, NULL, &act);
      69          84 :   if (act.sa_handler == SIG_DFL)
      70             :     {
      71          32 :       act.sa_handler = SIG_IGN;
      72          32 :       sigemptyset (&act.sa_mask);
      73          32 :       act.sa_flags = 0;
      74          32 :       sigaction (SIGPIPE, &act, NULL);
      75             :     }
      76          84 : }
      77             : 
      78             : 
      79             : /* Write the printable version of FD to the buffer BUF of length
      80             :    BUFLEN.  The printable version is the representation on the command
      81             :    line that the child process expects.  */
      82             : int
      83         821 : _gpgme_io_fd2str (char *buf, int buflen, int fd)
      84             : {
      85         821 :   return snprintf (buf, buflen, "%d", fd);
      86             : }
      87             : 
      88             : 
      89             : /* The table to hold notification handlers.  We use a linear search
      90             :    and extend the table as needed.  */
      91             : struct notify_table_item_s
      92             : {
      93             :   int fd;  /* -1 indicates an unused entry.  */
      94             :   _gpgme_close_notify_handler_t handler;
      95             :   void *value;
      96             : };
      97             : typedef struct notify_table_item_s *notify_table_item_t;
      98             : 
      99             : static notify_table_item_t notify_table;
     100             : static size_t notify_table_size;
     101             : DEFINE_STATIC_LOCK (notify_table_lock);
     102             : 
     103             : 
     104             : 
     105             : int
     106        5764 : _gpgme_io_read (int fd, void *buffer, size_t count)
     107             : {
     108             :   int nread;
     109        5764 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
     110             :               "buffer=%p, count=%u", buffer, count);
     111             : 
     112             :   do
     113             :     {
     114        5762 :       nread = _gpgme_ath_read (fd, buffer, count);
     115             :     }
     116        5740 :   while (nread == -1 && errno == EINTR);
     117             : 
     118        5740 :   TRACE_LOGBUF (buffer, nread);
     119        5743 :   return TRACE_SYSRES (nread);
     120             : }
     121             : 
     122             : 
     123             : int
     124         707 : _gpgme_io_write (int fd, const void *buffer, size_t count)
     125             : {
     126             :   int nwritten;
     127         707 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
     128             :               "buffer=%p, count=%u", buffer, count);
     129         707 :   TRACE_LOGBUF (buffer, count);
     130             : 
     131             :   do
     132             :     {
     133         707 :       nwritten = _gpgme_ath_write (fd, buffer, count);
     134             :     }
     135         707 :   while (nwritten == -1 && errno == EINTR);
     136             : 
     137         707 :   return TRACE_SYSRES (nwritten);
     138             : }
     139             : 
     140             : 
     141             : int
     142        1751 : _gpgme_io_pipe (int filedes[2], int inherit_idx)
     143             : {
     144             :   int saved_errno;
     145             :   int err;
     146        1751 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
     147             :               "inherit_idx=%i (GPGME uses it for %s)",
     148             :               inherit_idx, inherit_idx ? "reading" : "writing");
     149             : 
     150        1752 :   err = pipe (filedes);
     151        1750 :   if (err < 0)
     152           0 :     return TRACE_SYSRES (err);
     153             : 
     154             :   /* FIXME: Should get the old flags first.  */
     155        1750 :   err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
     156        1751 :   saved_errno = errno;
     157        1751 :   if (err < 0)
     158             :     {
     159           0 :       close (filedes[0]);
     160           0 :       close (filedes[1]);
     161             :     }
     162        1751 :   errno = saved_errno;
     163        1750 :   if (err)
     164           0 :     return TRACE_SYSRES (err);
     165             : 
     166        1750 :   return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
     167             : }
     168             : 
     169             : 
     170             : int
     171        3794 : _gpgme_io_close (int fd)
     172             : {
     173             :   int res;
     174        3794 :   _gpgme_close_notify_handler_t handler = NULL;
     175             :   void *handler_value;
     176             :   int idx;
     177             : 
     178        3794 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
     179             : 
     180        3794 :   if (fd == -1)
     181             :     {
     182           0 :       errno = EINVAL;
     183           0 :       return TRACE_SYSRES (-1);
     184             :     }
     185             : 
     186             :   /* First call the notify handler.  */
     187        3794 :   LOCK (notify_table_lock);
     188      843975 :   for (idx=0; idx < notify_table_size; idx++)
     189             :     {
     190      406331 :       if (notify_table[idx].fd == fd)
     191             :         {
     192           0 :           handler       = notify_table[idx].handler;
     193           0 :           handler_value = notify_table[idx].value;
     194           0 :           notify_table[idx].handler = NULL;
     195           0 :           notify_table[idx].value = NULL;
     196           0 :           notify_table[idx].fd = -1; /* Mark slot as free.  */
     197           0 :           break;
     198             :         }
     199             :     }
     200        3794 :   UNLOCK (notify_table_lock);
     201        3792 :   if (handler)
     202             :     {
     203        2732 :       TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
     204        2732 :       handler (fd, handler_value);
     205             :     }
     206             : 
     207             :   /* Then do the close.  */
     208        3790 :   res = close (fd);
     209        3790 :   return TRACE_SYSRES (res);
     210             : }
     211             : 
     212             : 
     213             : int
     214        2495 : _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
     215             :                             void *value)
     216             : {
     217        2495 :   int res = 0;
     218             :   int idx;
     219             : 
     220        2495 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
     221             :               "close_handler=%p/%p", handler, value);
     222             : 
     223        2494 :   assert (fd != -1);
     224             : 
     225        2494 :   LOCK (notify_table_lock);
     226       57646 :   for (idx=0; idx < notify_table_size; idx++)
     227       56662 :     if (notify_table[idx].fd == -1)
     228        1518 :       break;
     229        2502 :   if (idx == notify_table_size)
     230             :     {
     231             :       /* We need to increase the size of the table.  The approach we
     232             :          take is straightforward to minimize the risk of bugs.  */
     233             :       notify_table_item_t newtbl;
     234          81 :       size_t newsize = notify_table_size + 64;
     235             : 
     236          81 :       newtbl = calloc (newsize, sizeof *newtbl);
     237          81 :       if (!newtbl)
     238             :         {
     239           0 :           res = -1;
     240           0 :           goto leave;
     241             :         }
     242         785 :       for (idx=0; idx < notify_table_size; idx++)
     243         704 :         newtbl[idx] = notify_table[idx];
     244        5265 :       for (; idx < newsize; idx++)
     245             :         {
     246        5184 :           newtbl[idx].fd = -1;
     247        5184 :           newtbl[idx].handler = NULL;
     248        5184 :           newtbl[idx].value = NULL;
     249             :         }
     250          81 :       free (notify_table);
     251          81 :       notify_table = newtbl;
     252          81 :       idx = notify_table_size;
     253          81 :       notify_table_size = newsize;
     254             :     }
     255        2502 :   notify_table[idx].fd = fd;
     256        2502 :   notify_table[idx].handler = handler;
     257        2502 :   notify_table[idx].value = value;
     258             : 
     259             :  leave:
     260        2502 :   UNLOCK (notify_table_lock);
     261             : 
     262        2506 :   return TRACE_SYSRES (res);
     263             : }
     264             : 
     265             : 
     266             : int
     267         379 : _gpgme_io_set_nonblocking (int fd)
     268             : {
     269             :   int flags;
     270             :   int res;
     271         379 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
     272             : 
     273         379 :   flags = fcntl (fd, F_GETFL, 0);
     274         379 :   if (flags == -1)
     275           0 :     return TRACE_SYSRES (-1);
     276         379 :   flags |= O_NONBLOCK;
     277         379 :   res = fcntl (fd, F_SETFL, flags);
     278         379 :   return TRACE_SYSRES (res);
     279             : }
     280             : 
     281             : 
     282             : static long int
     283        1211 : get_max_fds (void)
     284             : {
     285        1211 :   const char *source = NULL;
     286        1211 :   long int fds = -1;
     287             :   int rc;
     288             : 
     289             :   /* Under Linux we can figure out the highest used file descriptor by
     290             :    * reading /proc/self/fd.  This is in the common cases much fast than
     291             :    * for example doing 4096 close calls where almost all of them will
     292             :    * fail.  */
     293             : #ifdef __linux__
     294             :   {
     295        1211 :     DIR *dir = NULL;
     296             :     struct dirent *dir_entry;
     297             :     const char *s;
     298             :     int x;
     299             : 
     300        1211 :     dir = opendir ("/proc/self/fd");
     301        1211 :     if (dir)
     302             :       {
     303      137220 :         while ((dir_entry = readdir (dir)))
     304             :           {
     305      134798 :             s = dir_entry->d_name;
     306      134798 :             if ( *s < '0' || *s > '9')
     307        2422 :               continue;
     308      132376 :             x = atoi (s);
     309      132376 :             if (x > fds)
     310      132376 :               fds = x;
     311             :           }
     312        1211 :         closedir (dir);
     313             :       }
     314        1211 :     if (fds != -1)
     315             :       {
     316        1211 :         fds++;
     317        1211 :         source = "/proc";
     318             :       }
     319             :     }
     320             : #endif /* __linux__ */
     321             : 
     322             : #ifdef RLIMIT_NOFILE
     323        1211 :   if (fds == -1)
     324             :     {
     325             :       struct rlimit rl;
     326           0 :       rc = getrlimit (RLIMIT_NOFILE, &rl);
     327           0 :       if (rc == 0)
     328             :         {
     329           0 :           source = "RLIMIT_NOFILE";
     330           0 :           fds = rl.rlim_max;
     331             :         }
     332             :     }
     333             : #endif
     334             : #ifdef RLIMIT_OFILE
     335        1211 :   if (fds == -1)
     336             :     {
     337             :       struct rlimit rl;
     338           0 :       rc = getrlimit (RLIMIT_OFILE, &rl);
     339           0 :       if (rc == 0)
     340             :         {
     341           0 :           source = "RLIMIT_OFILE";
     342           0 :           fds = rl.rlim_max;
     343             :         }
     344             :     }
     345             : #endif
     346             : #ifdef _SC_OPEN_MAX
     347        1211 :   if (fds == -1)
     348             :     {
     349             :       long int scres;
     350           0 :       scres = sysconf (_SC_OPEN_MAX);
     351           0 :       if (scres >= 0)
     352             :         {
     353           0 :           source = "_SC_OPEN_MAX";
     354           0 :           return scres;
     355             :         }
     356             :     }
     357             : #endif
     358             : #ifdef OPEN_MAX
     359             :   if (fds == -1)
     360             :     {
     361             :       source = "OPEN_MAX";
     362             :       fds = OPEN_MAX;
     363             :     }
     364             : #endif
     365             : 
     366             : #if !defined(RLIMIT_NOFILE) && !defined(RLIMIT_OFILE) \
     367             :   && !defined(_SC_OPEN_MAX) && !defined(OPEN_MAX)
     368             : #warning "No known way to get the maximum number of file descriptors."
     369             : #endif
     370        1211 :   if (fds == -1)
     371             :     {
     372           0 :       source = "arbitrary";
     373             :       /* Arbitrary limit.  */
     374           0 :       fds = 1024;
     375             :     }
     376             : 
     377             :   /* AIX returns INT32_MAX instead of a proper value.  We assume that
     378             :    * this is always an error and use a more reasonable limit.  */
     379             : #ifdef INT32_MAX
     380        1211 :   if (fds == INT32_MAX)
     381             :     {
     382           0 :       source = "aix-fix";
     383           0 :       fds = 1024;
     384             :     }
     385             : #endif
     386             : 
     387        1211 :   TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
     388        1211 :   return fds;
     389             : }
     390             : 
     391             : 
     392             : int
     393        1207 : _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
     394             : {
     395             :   int status;
     396             :   pid_t ret;
     397             : 
     398        1207 :   *r_status = 0;
     399        1207 :   *r_signal = 0;
     400             :   do
     401        1206 :     ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
     402         997 :   while (ret == (pid_t)(-1) && errno == EINTR);
     403             : 
     404         998 :   if (ret == pid)
     405             :     {
     406         998 :       if (WIFSIGNALED (status))
     407             :         {
     408           0 :           *r_status = 4; /* Need some value here.  */
     409           0 :           *r_signal = WTERMSIG (status);
     410             :         }
     411         998 :       else if (WIFEXITED (status))
     412         998 :         *r_status = WEXITSTATUS (status);
     413             :       else
     414           0 :         *r_status = 4; /* Oops.  */
     415         998 :       return 1;
     416             :     }
     417           0 :   return 0;
     418             : }
     419             : 
     420             : 
     421             : /* Returns 0 on success, -1 on error.  */
     422             : int
     423         976 : _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
     424             :                  struct spawn_fd_item_s *fd_list,
     425             :                  void (*atfork) (void *opaque, int reserved),
     426             :                  void *atforkvalue, pid_t *r_pid)
     427             : {
     428             :   pid_t pid;
     429             :   int i;
     430             :   int status;
     431             :   int signo;
     432             : 
     433         976 :   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
     434             :               "path=%s", path);
     435         969 :   i = 0;
     436       13730 :   while (argv[i])
     437             :     {
     438       11785 :       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
     439       11792 :       i++;
     440             :     }
     441        2722 :   for (i = 0; fd_list[i].fd != -1; i++)
     442        1746 :     if (fd_list[i].dup_to == -1)
     443         831 :       TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
     444             :     else
     445         915 :       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
     446             : 
     447         976 :   pid = fork ();
     448        2418 :   if (pid == -1)
     449           0 :     return TRACE_SYSRES (-1);
     450             : 
     451        2418 :   if (!pid)
     452             :     {
     453             :       /* Intermediate child to prevent zombie processes.  */
     454        1211 :       if ((pid = fork ()) == 0)
     455             :         {
     456        1211 :           int max_fds = get_max_fds ();
     457             :           int fd;
     458             : 
     459             :           /* Child.  */
     460        1211 :           int seen_stdin = 0;
     461        1211 :           int seen_stdout = 0;
     462        1211 :           int seen_stderr = 0;
     463             : 
     464        1211 :           if (atfork)
     465           8 :             atfork (atforkvalue, 0);
     466             : 
     467             :           /* First close all fds which will not be inherited.  */
     468      248042 :           for (fd = 0; fd < max_fds; fd++)
     469             :             {
     470      835912 :               for (i = 0; fd_list[i].fd != -1; i++)
     471      591376 :                 if (fd_list[i].fd == fd)
     472        2295 :                   break;
     473      246831 :               if (fd_list[i].fd == -1)
     474      244536 :                 close (fd);
     475             :             }
     476             : 
     477             :           /* And now dup and close those to be duplicated.  */
     478        3506 :           for (i = 0; fd_list[i].fd != -1; i++)
     479             :             {
     480             :               int child_fd;
     481             :               int res;
     482             : 
     483        2295 :               if (fd_list[i].dup_to != -1)
     484        1073 :                 child_fd = fd_list[i].dup_to;
     485             :               else
     486        1222 :                 child_fd = fd_list[i].fd;
     487             : 
     488        2295 :               if (child_fd == 0)
     489           0 :                 seen_stdin = 1;
     490        2295 :               else if (child_fd == 1)
     491        1073 :                 seen_stdout = 1;
     492        1222 :               else if (child_fd == 2)
     493           0 :                 seen_stderr = 1;
     494             : 
     495        2295 :               if (fd_list[i].dup_to == -1)
     496        1222 :                 continue;
     497             : 
     498        1073 :               res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
     499        1073 :               if (res < 0)
     500             :                 {
     501             : #if 0
     502             :                   /* FIXME: The debug file descriptor is not
     503             :                      dup'ed anyway, so we can't see this.  */
     504             :                   TRACE_LOG1 ("dup2 failed in child: %s\n",
     505             :                               strerror (errno));
     506             : #endif
     507           0 :                   _exit (8);
     508             :                 }
     509             : 
     510        1073 :               close (fd_list[i].fd);
     511             :             }
     512             : 
     513        1211 :           if (! seen_stdin || ! seen_stdout || !seen_stderr)
     514             :             {
     515        1211 :               fd = open ("/dev/null", O_RDWR);
     516        1211 :               if (fd == -1)
     517             :                 {
     518             :                   /* The debug file descriptor is not dup'ed, so we
     519             :                      can't do a trace output.  */
     520           0 :                   _exit (8);
     521             :                 }
     522             :               /* Make sure that the process has connected stdin.  */
     523        1211 :               if (! seen_stdin && fd != 0)
     524             :                 {
     525           0 :                   if (dup2 (fd, 0) == -1)
     526           0 :                     _exit (8);
     527             :                 }
     528        1211 :               if (! seen_stdout && fd != 1)
     529             :                 {
     530         138 :                   if (dup2 (fd, 1) == -1)
     531           0 :                     _exit (8);
     532             :                 }
     533        1211 :               if (! seen_stderr && fd != 2)
     534             :                 {
     535        1211 :                   if (dup2 (fd, 2) == -1)
     536           0 :                     _exit (8);
     537             :                 }
     538        1211 :               if (fd != 0 && fd != 1 && fd != 2)
     539           0 :                 close (fd);
     540             :             }
     541             : 
     542        1211 :           execv (path, (char *const *) argv);
     543             :           /* Hmm: in that case we could write a special status code to the
     544             :              status-pipe.  */
     545        1211 :           _exit (8);
     546             :           /* End child.  */
     547             :         }
     548           0 :       if (pid == -1)
     549           0 :         _exit (1);
     550             :       else
     551           0 :         _exit (0);
     552             :     }
     553             : 
     554        1207 :   TRACE_LOG1 ("waiting for child process pid=%i", pid);
     555        1207 :   _gpgme_io_waitpid (pid, 1, &status, &signo);
     556         998 :   if (status)
     557           0 :     return TRACE_SYSRES (-1);
     558             : 
     559        2784 :   for (i = 0; fd_list[i].fd != -1; i++)
     560             :     {
     561        1790 :       if (! (flags & IOSPAWN_FLAG_NOCLOSE))
     562        1782 :         _gpgme_io_close (fd_list[i].fd);
     563             :       /* No handle translation.  */
     564        1786 :       fd_list[i].peer_name = fd_list[i].fd;
     565             :     }
     566             : 
     567         994 :   if (r_pid)
     568         482 :     *r_pid = pid;
     569             : 
     570         994 :   return TRACE_SYSRES (0);
     571             : }
     572             : 
     573             : 
     574             : /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
     575             :    nothing to select, > 0 = number of signaled fds.  */
     576             : int
     577       11718 : _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
     578             : {
     579             :   fd_set readfds;
     580             :   fd_set writefds;
     581             :   unsigned int i;
     582             :   int any;
     583             :   int max_fd;
     584             :   int n;
     585             :   int count;
     586             :   /* Use a 1s timeout.  */
     587       11718 :   struct timeval timeout = { 1, 0 };
     588       11718 :   void *dbg_help = NULL;
     589       11718 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
     590             :               "nfds=%u, nonblock=%u", nfds, nonblock);
     591             : 
     592       11719 :   FD_ZERO (&readfds);
     593       23263 :   FD_ZERO (&writefds);
     594       11723 :   max_fd = 0;
     595       11723 :   if (nonblock)
     596        6114 :     timeout.tv_sec = 0;
     597             : 
     598       11723 :   TRACE_SEQ (dbg_help, "select on [ ");
     599             : 
     600       72384 :   any = 0;
     601      134595 :   for (i = 0; i < nfds; i++)
     602             :     {
     603      122871 :       if (fds[i].fd == -1)
     604       45691 :         continue;
     605       77180 :       if (fds[i].for_read)
     606             :         {
     607       75158 :           if (fds[i].fd >= FD_SETSIZE)
     608             :             {
     609       60662 :               TRACE_END (dbg_help, " -BAD- ]");
     610           0 :               gpg_err_set_errno (EMFILE);
     611           0 :               return TRACE_SYSRES (-1);
     612             :             }
     613       14496 :           assert (!FD_ISSET (fds[i].fd, &readfds));
     614       14496 :           FD_SET (fds[i].fd, &readfds);
     615       14496 :           if (fds[i].fd > max_fd)
     616       14431 :             max_fd = fds[i].fd;
     617       14496 :           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
     618       14498 :           any = 1;
     619             :         }
     620        2022 :       else if (fds[i].for_write)
     621             :         {
     622        2022 :           if (fds[i].fd >= FD_SETSIZE)
     623             :             {
     624           0 :               TRACE_END (dbg_help, " -BAD- ]");
     625           0 :               gpg_err_set_errno (EMFILE);
     626           0 :               return TRACE_SYSRES (-1);
     627             :             }
     628        2022 :           assert (!FD_ISSET (fds[i].fd, &writefds));
     629        2022 :           FD_SET (fds[i].fd, &writefds);
     630        2022 :           if (fds[i].fd > max_fd)
     631        1939 :             max_fd = fds[i].fd;
     632        2022 :           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
     633        2022 :           any = 1;
     634             :         }
     635       16520 :       fds[i].signaled = 0;
     636             :     }
     637       11724 :   TRACE_END (dbg_help, "]");
     638       17985 :   if (!any)
     639         233 :     return TRACE_SYSRES (0);
     640             : 
     641             :   do
     642             :     {
     643       17742 :       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
     644             :                                  &timeout);
     645             :     }
     646       11655 :   while (count < 0 && errno == EINTR);
     647       11665 :   if (count < 0)
     648           0 :     return TRACE_SYSRES (-1);
     649             : 
     650       11665 :   TRACE_SEQ (dbg_help, "select OK [ ");
     651       11665 :   if (TRACE_ENABLED (dbg_help))
     652             :     {
     653           0 :       for (i = 0; i <= max_fd; i++)
     654             :         {
     655           0 :           if (FD_ISSET (i, &readfds))
     656           0 :             TRACE_ADD1 (dbg_help, "r0x%x ", i);
     657           0 :           if (FD_ISSET (i, &writefds))
     658           0 :             TRACE_ADD1 (dbg_help, "w0x%x ", i);
     659             :         }
     660           0 :       TRACE_END (dbg_help, "]");
     661             :     }
     662             : 
     663             :   /* The variable N is used to optimize it a little bit.  */
     664       26874 :   for (n = count, i = 0; i < nfds && n; i++)
     665             :     {
     666       15211 :       if (fds[i].fd == -1)
     667             :         ;
     668       14749 :       else if (fds[i].for_read)
     669             :         {
     670       12737 :           if (FD_ISSET (fds[i].fd, &readfds))
     671             :             {
     672       10209 :               fds[i].signaled = 1;
     673       10209 :               n--;
     674             :             }
     675             :         }
     676        2012 :       else if (fds[i].for_write)
     677             :         {
     678        2012 :           if (FD_ISSET (fds[i].fd, &writefds))
     679             :             {
     680        2012 :               fds[i].signaled = 1;
     681        2012 :               n--;
     682             :             }
     683             :         }
     684             :     }
     685       11663 :   return TRACE_SYSRES (count);
     686             : }
     687             : 
     688             : 
     689             : int
     690         124 : _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
     691             : {
     692             :   int nread;
     693             :   int saved_errno;
     694             :   struct iovec *iov;
     695         124 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
     696             :               "msg=%p, flags=%i", msg, flags);
     697             : 
     698         124 :   nread = 0;
     699         124 :   iov = msg->msg_iov;
     700         372 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     701             :     {
     702         124 :       nread += iov->iov_len;
     703         124 :       iov++;
     704             :     }
     705             : 
     706         124 :   TRACE_LOG1 ("about to receive %d bytes", nread);
     707             : 
     708             :   do
     709             :     {
     710         124 :       nread = _gpgme_ath_recvmsg (fd, msg, flags);
     711             :     }
     712         124 :   while (nread == -1 && errno == EINTR);
     713         124 :   saved_errno = errno;
     714         124 :   if (nread > 0)
     715             :     {
     716         124 :       int nr = nread;
     717             : 
     718         124 :       iov = msg->msg_iov;
     719         372 :       while (nr > 0)
     720             :         {
     721         124 :           int len = nr > iov->iov_len ? iov->iov_len : nr;
     722         124 :           TRACE_LOGBUF (msg->msg_iov->iov_base, len);
     723         124 :           iov++;
     724         124 :           nr -= len;
     725             :         }
     726             :     }
     727         124 :   errno = saved_errno;
     728         124 :   return TRACE_SYSRES (nread);
     729             : }
     730             : 
     731             : 
     732             : int
     733         240 : _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
     734             : {
     735             :   int nwritten;
     736             :   struct iovec *iov;
     737         240 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
     738             :               "msg=%p, flags=%i", msg, flags);
     739             : 
     740         240 :   nwritten = 0;
     741         240 :   iov = msg->msg_iov;
     742         720 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     743             :     {
     744         240 :       nwritten += iov->iov_len;
     745         240 :       iov++;
     746             :     }
     747             : 
     748         240 :   TRACE_LOG1 ("about to receive %d bytes", nwritten);
     749         240 :   iov = msg->msg_iov;
     750         720 :   while (nwritten > 0)
     751             :     {
     752         240 :       int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
     753         240 :       TRACE_LOGBUF (msg->msg_iov->iov_base, len);
     754         240 :       iov++;
     755         240 :       nwritten -= len;
     756             :     }
     757             : 
     758             :   do
     759             :     {
     760         240 :       nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
     761             :     }
     762         240 :   while (nwritten == -1 && errno == EINTR);
     763         240 :   return TRACE_SYSRES (nwritten);
     764             : }
     765             : 
     766             : 
     767             : int
     768          30 : _gpgme_io_dup (int fd)
     769             : {
     770             :   int new_fd;
     771             : 
     772             :   do
     773          30 :     new_fd = dup (fd);
     774          30 :   while (new_fd == -1 && errno == EINTR);
     775             : 
     776          30 :   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
     777             : 
     778          30 :   return new_fd;
     779             : }
     780             : 
     781             : 
     782             : int
     783           2 : _gpgme_io_socket (int domain, int type, int proto)
     784             : {
     785             :   int res;
     786             : 
     787           2 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
     788             :               "type=%i, proto=%i", type, proto);
     789             : 
     790           2 :   res = socket (domain, type, proto);
     791             : 
     792           2 :   return TRACE_SYSRES (res);
     793             : }
     794             : 
     795             : 
     796             : int
     797           2 : _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
     798             : {
     799             :   int res;
     800             : 
     801           2 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
     802             :               "addr=%p, addrlen=%i", addr, addrlen);
     803             : 
     804             :   do
     805           2 :     res = ath_connect (fd, addr, addrlen);
     806           2 :   while (res == -1 && errno == EINTR);
     807             : 
     808           2 :   return TRACE_SYSRES (res);
     809             : }

Generated by: LCOV version 1.11