LCOV - code coverage report
Current view: top level - src - posix-io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 280 337 83.1 %
Date: 2016-09-12 13:07:23 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 <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             : #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          59 : _gpgme_io_subsystem_init (void)
      65             : {
      66             :   struct sigaction act;
      67             : 
      68          59 :   sigaction (SIGPIPE, NULL, &act);
      69          59 :   if (act.sa_handler == SIG_DFL)
      70             :     {
      71          30 :       act.sa_handler = SIG_IGN;
      72          30 :       sigemptyset (&act.sa_mask);
      73          30 :       act.sa_flags = 0;
      74          30 :       sigaction (SIGPIPE, &act, NULL);
      75             :     }
      76          59 : }
      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         494 : _gpgme_io_fd2str (char *buf, int buflen, int fd)
      84             : {
      85         494 :   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        2731 : _gpgme_io_read (int fd, void *buffer, size_t count)
     107             : {
     108             :   int nread;
     109        2731 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
     110             :               "buffer=%p, count=%u", buffer, count);
     111             : 
     112             :   do
     113             :     {
     114        2731 :       nread = _gpgme_ath_read (fd, buffer, count);
     115             :     }
     116        2733 :   while (nread == -1 && errno == EINTR);
     117             : 
     118        2733 :   TRACE_LOGBUF (buffer, nread);
     119        2733 :   return TRACE_SYSRES (nread);
     120             : }
     121             : 
     122             : 
     123             : int
     124         530 : _gpgme_io_write (int fd, const void *buffer, size_t count)
     125             : {
     126             :   int nwritten;
     127         530 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
     128             :               "buffer=%p, count=%u", buffer, count);
     129         530 :   TRACE_LOGBUF (buffer, count);
     130             : 
     131             :   do
     132             :     {
     133         530 :       nwritten = _gpgme_ath_write (fd, buffer, count);
     134             :     }
     135         530 :   while (nwritten == -1 && errno == EINTR);
     136             : 
     137         530 :   return TRACE_SYSRES (nwritten);
     138             : }
     139             : 
     140             : 
     141             : int
     142        1123 : _gpgme_io_pipe (int filedes[2], int inherit_idx)
     143             : {
     144             :   int saved_errno;
     145             :   int err;
     146        1123 :   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        1123 :   err = pipe (filedes);
     151        1123 :   if (err < 0)
     152           0 :     return TRACE_SYSRES (err);
     153             : 
     154             :   /* FIXME: Should get the old flags first.  */
     155        1123 :   err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
     156        1125 :   saved_errno = errno;
     157        1125 :   if (err < 0)
     158             :     {
     159           0 :       close (filedes[0]);
     160           0 :       close (filedes[1]);
     161             :     }
     162        1125 :   errno = saved_errno;
     163        1125 :   if (err)
     164           0 :     return TRACE_SYSRES (err);
     165             : 
     166        1125 :   return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
     167             : }
     168             : 
     169             : 
     170             : int
     171        2270 : _gpgme_io_close (int fd)
     172             : {
     173             :   int res;
     174        2270 :   _gpgme_close_notify_handler_t handler = NULL;
     175             :   void *handler_value;
     176             :   int idx;
     177             : 
     178        2270 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
     179             : 
     180        2270 :   if (fd == -1)
     181             :     {
     182           0 :       errno = EINVAL;
     183           0 :       return TRACE_SYSRES (-1);
     184             :     }
     185             : 
     186             :   /* First call the notify handler.  */
     187        2270 :   LOCK (notify_table_lock);
     188       16978 :   for (idx=0; idx < notify_table_size; idx++)
     189             :     {
     190       16223 :       if (notify_table[idx].fd == fd)
     191             :         {
     192        1515 :           handler       = notify_table[idx].handler;
     193        1515 :           handler_value = notify_table[idx].value;
     194        1515 :           notify_table[idx].handler = NULL;
     195        1515 :           notify_table[idx].value = NULL;
     196        1515 :           notify_table[idx].fd = -1; /* Mark slot as free.  */
     197        1515 :           break;
     198             :         }
     199             :     }
     200        2270 :   UNLOCK (notify_table_lock);
     201        2270 :   if (handler)
     202             :     {
     203        1515 :       TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
     204        1515 :       handler (fd, handler_value);
     205             :     }
     206             : 
     207             :   /* Then do the close.  */
     208        2270 :   res = close (fd);
     209        2270 :   return TRACE_SYSRES (res);
     210             : }
     211             : 
     212             : 
     213             : int
     214        1532 : _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
     215             :                             void *value)
     216             : {
     217        1532 :   int res = 0;
     218             :   int idx;
     219             : 
     220        1532 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
     221             :               "close_handler=%p/%p", handler, value);
     222             : 
     223        1532 :   assert (fd != -1);
     224             : 
     225        1532 :   LOCK (notify_table_lock);
     226        5970 :   for (idx=0; idx < notify_table_size; idx++)
     227        5916 :     if (notify_table[idx].fd == -1)
     228        1478 :       break;
     229        1532 :   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          54 :       size_t newsize = notify_table_size + 64;
     235             : 
     236          54 :       newtbl = calloc (newsize, sizeof *newtbl);
     237          54 :       if (!newtbl)
     238             :         {
     239           0 :           res = -1;
     240           0 :           goto leave;
     241             :         }
     242          54 :       for (idx=0; idx < notify_table_size; idx++)
     243           0 :         newtbl[idx] = notify_table[idx];
     244        3510 :       for (; idx < newsize; idx++)
     245             :         {
     246        3456 :           newtbl[idx].fd = -1;
     247        3456 :           newtbl[idx].handler = NULL;
     248        3456 :           newtbl[idx].value = NULL;
     249             :         }
     250          54 :       free (notify_table);
     251          54 :       notify_table = newtbl;
     252          54 :       idx = notify_table_size;
     253          54 :       notify_table_size = newsize;
     254             :     }
     255        1532 :   notify_table[idx].fd = fd;
     256        1532 :   notify_table[idx].handler = handler;
     257        1532 :   notify_table[idx].value = value;
     258             : 
     259             :  leave:
     260        1532 :   UNLOCK (notify_table_lock);
     261             : 
     262        1532 :   return TRACE_SYSRES (res);
     263             : }
     264             : 
     265             : 
     266             : int
     267         210 : _gpgme_io_set_nonblocking (int fd)
     268             : {
     269             :   int flags;
     270             :   int res;
     271         210 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
     272             : 
     273         210 :   flags = fcntl (fd, F_GETFL, 0);
     274         210 :   if (flags == -1)
     275           0 :     return TRACE_SYSRES (-1);
     276         210 :   flags |= O_NONBLOCK;
     277         210 :   res = fcntl (fd, F_SETFL, flags);
     278         210 :   return TRACE_SYSRES (res);
     279             : }
     280             : 
     281             : 
     282             : static long int
     283         638 : get_max_fds (void)
     284             : {
     285         638 :   char *source = NULL;
     286         638 :   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         638 :     DIR *dir = NULL;
     296             :     struct dirent *dir_entry;
     297             :     const char *s;
     298             :     int x;
     299             : 
     300         638 :     dir = opendir ("/proc/self/fd");
     301         638 :     if (dir)
     302             :       {
     303        7886 :         while ((dir_entry = readdir (dir)))
     304             :           {
     305        6610 :             s = dir_entry->d_name;
     306        6610 :             if ( *s < '0' || *s > '9')
     307        1276 :               continue;
     308        5334 :             x = atoi (s);
     309        5334 :             if (x > fds)
     310        5334 :               fds = x;
     311             :           }
     312         638 :         closedir (dir);
     313             :       }
     314         638 :     if (fds != -1)
     315             :       {
     316         638 :         fds++;
     317         638 :         source = "/proc";
     318             :       }
     319             :     }
     320             : #endif /* __linux__ */
     321             : 
     322             : #ifdef RLIMIT_NOFILE
     323         638 :   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         638 :   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         638 :   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         638 :   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         638 :   if (fds == INT32_MAX)
     381             :     {
     382           0 :       source = "aix-fix";
     383           0 :       fds = 1024;
     384             :     }
     385             : #endif
     386             : 
     387         638 :   TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
     388         638 :   return fds;
     389             : }
     390             : 
     391             : 
     392             : int
     393         638 : _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
     394             : {
     395             :   int status;
     396             :   pid_t ret;
     397             : 
     398         638 :   *r_status = 0;
     399         638 :   *r_signal = 0;
     400             :   do
     401         638 :     ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
     402         633 :   while (ret == (pid_t)(-1) && errno == EINTR);
     403             : 
     404         633 :   if (ret == pid)
     405             :     {
     406         633 :       if (WIFSIGNALED (status))
     407             :         {
     408           0 :           *r_status = 4; /* Need some value here.  */
     409           0 :           *r_signal = WTERMSIG (status);
     410             :         }
     411         633 :       else if (WIFEXITED (status))
     412         633 :         *r_status = WEXITSTATUS (status);
     413             :       else
     414           0 :         *r_status = 4; /* Oops.  */
     415         633 :       return 1;
     416             :     }
     417           0 :   return 0;
     418             : }
     419             : 
     420             : 
     421             : /* Returns 0 on success, -1 on error.  */
     422             : int
     423         637 : _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         637 :   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
     434             :               "path=%s", path);
     435         637 :   i = 0;
     436        8306 :   while (argv[i])
     437             :     {
     438        7032 :       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
     439        7032 :       i++;
     440             :     }
     441        1754 :   for (i = 0; fd_list[i].fd != -1; i++)
     442        1117 :     if (fd_list[i].dup_to == -1)
     443         504 :       TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
     444             :     else
     445         613 :       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
     446             : 
     447         637 :   pid = fork ();
     448        1276 :   if (pid == -1)
     449           0 :     return TRACE_SYSRES (-1);
     450             : 
     451        1276 :   if (!pid)
     452             :     {
     453             :       /* Intermediate child to prevent zombie processes.  */
     454         638 :       if ((pid = fork ()) == 0)
     455             :         {
     456         638 :           int max_fds = get_max_fds ();
     457             :           int fd;
     458             : 
     459             :           /* Child.  */
     460         638 :           int seen_stdin = 0;
     461         638 :           int seen_stdout = 0;
     462         638 :           int seen_stderr = 0;
     463             : 
     464         638 :           if (atfork)
     465           8 :             atfork (atforkvalue, 0);
     466             : 
     467             :           /* First close all fds which will not be inherited.  */
     468        6059 :           for (fd = 0; fd < max_fds; fd++)
     469             :             {
     470       14490 :               for (i = 0; fd_list[i].fd != -1; i++)
     471       10190 :                 if (fd_list[i].fd == fd)
     472        1121 :                   break;
     473        5421 :               if (fd_list[i].fd == -1)
     474        4300 :                 close (fd);
     475             :             }
     476             : 
     477             :           /* And now dup and close those to be duplicated.  */
     478        1759 :           for (i = 0; fd_list[i].fd != -1; i++)
     479             :             {
     480             :               int child_fd;
     481             :               int res;
     482             : 
     483        1121 :               if (fd_list[i].dup_to != -1)
     484         614 :                 child_fd = fd_list[i].dup_to;
     485             :               else
     486         507 :                 child_fd = fd_list[i].fd;
     487             : 
     488        1121 :               if (child_fd == 0)
     489           0 :                 seen_stdin = 1;
     490        1121 :               else if (child_fd == 1)
     491         614 :                 seen_stdout = 1;
     492         507 :               else if (child_fd == 2)
     493           0 :                 seen_stderr = 1;
     494             : 
     495        1121 :               if (fd_list[i].dup_to == -1)
     496         507 :                 continue;
     497             : 
     498         614 :               res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
     499         614 :               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         614 :               close (fd_list[i].fd);
     511             :             }
     512             : 
     513         638 :           if (! seen_stdin || ! seen_stdout || !seen_stderr)
     514             :             {
     515         638 :               fd = open ("/dev/null", O_RDWR);
     516         638 :               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         638 :               if (! seen_stdin && fd != 0)
     524             :                 {
     525           0 :                   if (dup2 (fd, 0) == -1)
     526           0 :                     _exit (8);
     527             :                 }
     528         638 :               if (! seen_stdout && fd != 1)
     529             :                 {
     530          24 :                   if (dup2 (fd, 1) == -1)
     531           0 :                     _exit (8);
     532             :                 }
     533         638 :               if (! seen_stderr && fd != 2)
     534             :                 {
     535         638 :                   if (dup2 (fd, 2) == -1)
     536           0 :                     _exit (8);
     537             :                 }
     538         638 :               if (fd != 0 && fd != 1 && fd != 2)
     539           0 :                 close (fd);
     540             :             }
     541             : 
     542         638 :           execv (path, (char *const *) argv);
     543             :           /* Hmm: in that case we could write a special status code to the
     544             :              status-pipe.  */
     545         638 :           _exit (8);
     546             :           /* End child.  */
     547             :         }
     548           0 :       if (pid == -1)
     549           0 :         _exit (1);
     550             :       else
     551           0 :         _exit (0);
     552             :     }
     553             : 
     554         638 :   TRACE_LOG1 ("waiting for child process pid=%i", pid);
     555         638 :   _gpgme_io_waitpid (pid, 1, &status, &signo);
     556         633 :   if (status)
     557           0 :     return TRACE_SYSRES (-1);
     558             : 
     559        1736 :   for (i = 0; fd_list[i].fd != -1; i++)
     560             :     {
     561        1104 :       if (! (flags & IOSPAWN_FLAG_NOCLOSE))
     562        1096 :         _gpgme_io_close (fd_list[i].fd);
     563             :       /* No handle translation.  */
     564        1103 :       fd_list[i].peer_name = fd_list[i].fd;
     565             :     }
     566             : 
     567         632 :   if (r_pid)
     568         273 :     *r_pid = pid;
     569             : 
     570         632 :   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        5714 : _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        5714 :   struct timeval timeout = { 1, 0 };
     588        5714 :   void *dbg_help = NULL;
     589        5714 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
     590             :               "nfds=%u, nonblock=%u", nfds, nonblock);
     591             : 
     592        5714 :   FD_ZERO (&readfds);
     593        5714 :   FD_ZERO (&writefds);
     594        5714 :   max_fd = 0;
     595        5714 :   if (nonblock)
     596        2964 :     timeout.tv_sec = 0;
     597             : 
     598        5714 :   TRACE_SEQ (dbg_help, "select on [ ");
     599             : 
     600        5714 :   any = 0;
     601       36178 :   for (i = 0; i < nfds; i++)
     602             :     {
     603       30464 :       if (fds[i].fd == -1)
     604       21803 :         continue;
     605        8661 :       if (fds[i].for_read)
     606             :         {
     607        7293 :           if (fds[i].fd >= FD_SETSIZE)
     608             :             {
     609           0 :               TRACE_END (dbg_help, " -BAD- ]");
     610           0 :               gpg_err_set_errno (EBADF);
     611           0 :               return TRACE_SYSRES (-1);
     612             :             }
     613        7293 :           assert (!FD_ISSET (fds[i].fd, &readfds));
     614        7293 :           FD_SET (fds[i].fd, &readfds);
     615        7293 :           if (fds[i].fd > max_fd)
     616        7268 :             max_fd = fds[i].fd;
     617        7293 :           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
     618        7293 :           any = 1;
     619             :         }
     620        1368 :       else if (fds[i].for_write)
     621             :         {
     622        1368 :           if (fds[i].fd >= FD_SETSIZE)
     623             :             {
     624           0 :               TRACE_END (dbg_help, " -BAD- ]");
     625           0 :               gpg_err_set_errno (EBADF);
     626           0 :               return TRACE_SYSRES (-1);
     627             :             }
     628        1368 :           assert (!FD_ISSET (fds[i].fd, &writefds));
     629        1368 :           FD_SET (fds[i].fd, &writefds);
     630        1368 :           if (fds[i].fd > max_fd)
     631        1322 :             max_fd = fds[i].fd;
     632        1368 :           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
     633        1368 :           any = 1;
     634             :         }
     635        8661 :       fds[i].signaled = 0;
     636             :     }
     637        5714 :   TRACE_END (dbg_help, "]");
     638        5714 :   if (!any)
     639          95 :     return TRACE_SYSRES (0);
     640             : 
     641             :   do
     642             :     {
     643        5619 :       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
     644             :                                  &timeout);
     645             :     }
     646        5622 :   while (count < 0 && errno == EINTR);
     647        5622 :   if (count < 0)
     648           0 :     return TRACE_SYSRES (-1);
     649             : 
     650        5622 :   TRACE_SEQ (dbg_help, "select OK [ ");
     651        5622 :   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       13086 :   for (n = count, i = 0; i < nfds && n; i++)
     665             :     {
     666        7464 :       if (fds[i].fd == -1)
     667             :         ;
     668        7326 :       else if (fds[i].for_read)
     669             :         {
     670        5968 :           if (FD_ISSET (fds[i].fd, &readfds))
     671             :             {
     672        4563 :               fds[i].signaled = 1;
     673        4563 :               n--;
     674             :             }
     675             :         }
     676        1358 :       else if (fds[i].for_write)
     677             :         {
     678        1358 :           if (FD_ISSET (fds[i].fd, &writefds))
     679             :             {
     680        1358 :               fds[i].signaled = 1;
     681        1358 :               n--;
     682             :             }
     683             :         }
     684             :     }
     685        5622 :   return TRACE_SYSRES (count);
     686             : }
     687             : 
     688             : 
     689             : int
     690         125 : _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
     691             : {
     692             :   int nread;
     693             :   int saved_errno;
     694             :   struct iovec *iov;
     695         125 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
     696             :               "msg=%p, flags=%i", msg, flags);
     697             : 
     698         125 :   nread = 0;
     699         125 :   iov = msg->msg_iov;
     700         375 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     701             :     {
     702         125 :       nread += iov->iov_len;
     703         125 :       iov++;
     704             :     }
     705             : 
     706         125 :   TRACE_LOG1 ("about to receive %d bytes", nread);
     707             : 
     708             :   do
     709             :     {
     710         125 :       nread = _gpgme_ath_recvmsg (fd, msg, flags);
     711             :     }
     712         125 :   while (nread == -1 && errno == EINTR);
     713         125 :   saved_errno = errno;
     714         125 :   if (nread > 0)
     715             :     {
     716         125 :       int nr = nread;
     717             : 
     718         125 :       iov = msg->msg_iov;
     719         375 :       while (nr > 0)
     720             :         {
     721         125 :           int len = nr > iov->iov_len ? iov->iov_len : nr;
     722         125 :           TRACE_LOGBUF (msg->msg_iov->iov_base, len);
     723         125 :           iov++;
     724         125 :           nr -= len;
     725             :         }
     726             :     }
     727         125 :   errno = saved_errno;
     728         125 :   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          22 : _gpgme_io_dup (int fd)
     769             : {
     770             :   int new_fd;
     771             : 
     772             :   do
     773          22 :     new_fd = dup (fd);
     774          22 :   while (new_fd == -1 && errno == EINTR);
     775             : 
     776          22 :   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
     777             : 
     778          22 :   return new_fd;
     779             : }
     780             : 
     781             : 
     782             : int
     783           1 : _gpgme_io_socket (int domain, int type, int proto)
     784             : {
     785             :   int res;
     786             : 
     787           1 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
     788             :               "type=%i, proto=%i", type, proto);
     789             : 
     790           1 :   res = socket (domain, type, proto);
     791             : 
     792           1 :   return TRACE_SYSRES (res);
     793             : }
     794             : 
     795             : 
     796             : int
     797           1 : _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
     798             : {
     799             :   int res;
     800             : 
     801           1 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
     802             :               "addr=%p, addrlen=%i", addr, addrlen);
     803             : 
     804             :   do
     805           1 :     res = ath_connect (fd, addr, addrlen);
     806           1 :   while (res == -1 && errno == EINTR);
     807             : 
     808           1 :   return TRACE_SYSRES (res);
     809             : }

Generated by: LCOV version 1.11