LCOV - code coverage report
Current view: top level - src - posix-io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 275 325 84.6 %
Date: 2017-03-02 17:11:10 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          95 : _gpgme_io_subsystem_init (void)
      65             : {
      66             :   struct sigaction act;
      67             : 
      68          95 :   sigaction (SIGPIPE, NULL, &act);
      69          95 :   if (act.sa_handler == SIG_DFL)
      70             :     {
      71          33 :       act.sa_handler = SIG_IGN;
      72          33 :       sigemptyset (&act.sa_mask);
      73          33 :       act.sa_flags = 0;
      74          33 :       sigaction (SIGPIPE, &act, NULL);
      75             :     }
      76          95 : }
      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        1013 : _gpgme_io_fd2str (char *buf, int buflen, int fd)
      84             : {
      85        1013 :   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        7234 : _gpgme_io_read (int fd, void *buffer, size_t count)
     107             : {
     108             :   int nread;
     109        7234 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
     110             :               "buffer=%p, count=%u", buffer, count);
     111             : 
     112             :   do
     113             :     {
     114        7234 :       nread = _gpgme_ath_read (fd, buffer, count);
     115             :     }
     116        7233 :   while (nread == -1 && errno == EINTR);
     117             : 
     118        7233 :   TRACE_LOGBUF (buffer, nread);
     119        7233 :   return TRACE_SYSRES (nread);
     120             : }
     121             : 
     122             : 
     123             : int
     124         804 : _gpgme_io_write (int fd, const void *buffer, size_t count)
     125             : {
     126             :   int nwritten;
     127         804 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
     128             :               "buffer=%p, count=%u", buffer, count);
     129         804 :   TRACE_LOGBUF (buffer, count);
     130             : 
     131             :   do
     132             :     {
     133         804 :       nwritten = _gpgme_ath_write (fd, buffer, count);
     134             :     }
     135         804 :   while (nwritten == -1 && errno == EINTR);
     136             : 
     137         804 :   return TRACE_SYSRES (nwritten);
     138             : }
     139             : 
     140             : 
     141             : int
     142        2634 : _gpgme_io_pipe (int filedes[2], int inherit_idx)
     143             : {
     144             :   int saved_errno;
     145             :   int err;
     146        2634 :   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        2634 :   err = pipe (filedes);
     151        2634 :   if (err < 0)
     152           0 :     return TRACE_SYSRES (err);
     153             : 
     154             :   /* FIXME: Should get the old flags first.  */
     155        2634 :   err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
     156        2634 :   saved_errno = errno;
     157        2634 :   if (err < 0)
     158             :     {
     159           0 :       close (filedes[0]);
     160           0 :       close (filedes[1]);
     161             :     }
     162        2634 :   errno = saved_errno;
     163        2634 :   if (err)
     164           0 :     return TRACE_SYSRES (err);
     165             : 
     166        2634 :   return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
     167             : }
     168             : 
     169             : 
     170             : int
     171        5311 : _gpgme_io_close (int fd)
     172             : {
     173             :   int res;
     174        5311 :   _gpgme_close_notify_handler_t handler = NULL;
     175             :   void *handler_value;
     176             :   int idx;
     177             : 
     178        5311 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
     179             : 
     180        5311 :   if (fd == -1)
     181             :     {
     182           0 :       errno = EINVAL;
     183           0 :       return TRACE_SYSRES (-1);
     184             :     }
     185             : 
     186             :   /* First call the notify handler.  */
     187        5311 :   LOCK (notify_table_lock);
     188       46447 :   for (idx=0; idx < notify_table_size; idx++)
     189             :     {
     190       44180 :       if (notify_table[idx].fd == fd)
     191             :         {
     192        3044 :           handler       = notify_table[idx].handler;
     193        3044 :           handler_value = notify_table[idx].value;
     194        3044 :           notify_table[idx].handler = NULL;
     195        3044 :           notify_table[idx].value = NULL;
     196        3044 :           notify_table[idx].fd = -1; /* Mark slot as free.  */
     197        3044 :           break;
     198             :         }
     199             :     }
     200        5311 :   UNLOCK (notify_table_lock);
     201        5311 :   if (handler)
     202             :     {
     203        3044 :       TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
     204        3044 :       handler (fd, handler_value);
     205             :     }
     206             : 
     207             :   /* Then do the close.  */
     208        5311 :   res = close (fd);
     209        5311 :   return TRACE_SYSRES (res);
     210             : }
     211             : 
     212             : 
     213             : int
     214        3066 : _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
     215             :                             void *value)
     216             : {
     217        3066 :   int res = 0;
     218             :   int idx;
     219             : 
     220        3066 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
     221             :               "close_handler=%p/%p", handler, value);
     222             : 
     223        3065 :   assert (fd != -1);
     224             : 
     225        3065 :   LOCK (notify_table_lock);
     226       15506 :   for (idx=0; idx < notify_table_size; idx++)
     227       15418 :     if (notify_table[idx].fd == -1)
     228        2977 :       break;
     229        3065 :   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          88 :       size_t newsize = notify_table_size + 64;
     235             : 
     236          88 :       newtbl = calloc (newsize, sizeof *newtbl);
     237          88 :       if (!newtbl)
     238             :         {
     239           0 :           res = -1;
     240           0 :           goto leave;
     241             :         }
     242         152 :       for (idx=0; idx < notify_table_size; idx++)
     243          64 :         newtbl[idx] = notify_table[idx];
     244        5720 :       for (; idx < newsize; idx++)
     245             :         {
     246        5632 :           newtbl[idx].fd = -1;
     247        5632 :           newtbl[idx].handler = NULL;
     248        5632 :           newtbl[idx].value = NULL;
     249             :         }
     250          88 :       free (notify_table);
     251          88 :       notify_table = newtbl;
     252          88 :       idx = notify_table_size;
     253          88 :       notify_table_size = newsize;
     254             :     }
     255        3065 :   notify_table[idx].fd = fd;
     256        3065 :   notify_table[idx].handler = handler;
     257        3065 :   notify_table[idx].value = value;
     258             : 
     259             :  leave:
     260        3065 :   UNLOCK (notify_table_lock);
     261             : 
     262        3065 :   return TRACE_SYSRES (res);
     263             : }
     264             : 
     265             : 
     266             : int
     267         352 : _gpgme_io_set_nonblocking (int fd)
     268             : {
     269             :   int flags;
     270             :   int res;
     271         352 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
     272             : 
     273         352 :   flags = fcntl (fd, F_GETFL, 0);
     274         352 :   if (flags == -1)
     275           0 :     return TRACE_SYSRES (-1);
     276         352 :   flags |= O_NONBLOCK;
     277         352 :   res = fcntl (fd, F_SETFL, flags);
     278         352 :   return TRACE_SYSRES (res);
     279             : }
     280             : 
     281             : 
     282             : static long int
     283        1734 : get_max_fds (void)
     284             : {
     285        1734 :   const char *source = NULL;
     286        1734 :   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 faster
     291             :    * than for example doing 4096 close calls where almost all of them
     292             :    * will fail.
     293             :    *
     294             :    * Unfortunately we can't call opendir between fork and exec in a
     295             :    * multi-threaded process because opendir uses malloc and thus a
     296             :    * mutex which may deadlock with a malloc in another thread.  Thus
     297             :    * the code is not used until we can have a opendir variant which
     298             :    * does not use malloc.  */
     299             : /* #ifdef __linux__ */
     300             : /*   { */
     301             : /*     DIR *dir = NULL; */
     302             : /*     struct dirent *dir_entry; */
     303             : /*     const char *s; */
     304             : /*     int x; */
     305             : 
     306             : /*     dir = opendir ("/proc/self/fd"); */
     307             : /*     if (dir) */
     308             : /*       { */
     309             : /*         while ((dir_entry = readdir (dir))) */
     310             : /*           { */
     311             : /*             s = dir_entry->d_name; */
     312             : /*             if ( *s < '0' || *s > '9') */
     313             : /*               continue; */
     314             : /*             x = atoi (s); */
     315             : /*             if (x > fds) */
     316             : /*               fds = x; */
     317             : /*           } */
     318             : /*         closedir (dir); */
     319             : /*       } */
     320             : /*     if (fds != -1) */
     321             : /*       { */
     322             : /*         fds++; */
     323             : /*         source = "/proc"; */
     324             : /*       } */
     325             : /*     } */
     326             : /* #endif /\* __linux__ *\/ */
     327             : 
     328             : #ifdef RLIMIT_NOFILE
     329        1734 :   if (fds == -1)
     330             :     {
     331             :       struct rlimit rl;
     332        1734 :       rc = getrlimit (RLIMIT_NOFILE, &rl);
     333        1734 :       if (rc == 0)
     334             :         {
     335        1734 :           source = "RLIMIT_NOFILE";
     336        1734 :           fds = rl.rlim_max;
     337             :         }
     338             :     }
     339             : #endif
     340             : #ifdef RLIMIT_OFILE
     341        1734 :   if (fds == -1)
     342             :     {
     343             :       struct rlimit rl;
     344           0 :       rc = getrlimit (RLIMIT_OFILE, &rl);
     345           0 :       if (rc == 0)
     346             :         {
     347           0 :           source = "RLIMIT_OFILE";
     348           0 :           fds = rl.rlim_max;
     349             :         }
     350             :     }
     351             : #endif
     352             : #ifdef _SC_OPEN_MAX
     353        1734 :   if (fds == -1)
     354             :     {
     355             :       long int scres;
     356           0 :       scres = sysconf (_SC_OPEN_MAX);
     357           0 :       if (scres >= 0)
     358             :         {
     359           0 :           source = "_SC_OPEN_MAX";
     360           0 :           return scres;
     361             :         }
     362             :     }
     363             : #endif
     364             : #ifdef OPEN_MAX
     365             :   if (fds == -1)
     366             :     {
     367             :       source = "OPEN_MAX";
     368             :       fds = OPEN_MAX;
     369             :     }
     370             : #endif
     371             : 
     372             : #if !defined(RLIMIT_NOFILE) && !defined(RLIMIT_OFILE) \
     373             :   && !defined(_SC_OPEN_MAX) && !defined(OPEN_MAX)
     374             : #warning "No known way to get the maximum number of file descriptors."
     375             : #endif
     376        1734 :   if (fds == -1)
     377             :     {
     378           0 :       source = "arbitrary";
     379             :       /* Arbitrary limit.  */
     380           0 :       fds = 1024;
     381             :     }
     382             : 
     383             :   /* AIX returns INT32_MAX instead of a proper value.  We assume that
     384             :    * this is always an error and use a more reasonable limit.  */
     385             : #ifdef INT32_MAX
     386        1734 :   if (fds == INT32_MAX)
     387             :     {
     388           0 :       source = "aix-fix";
     389           0 :       fds = 1024;
     390             :     }
     391             : #endif
     392             : 
     393        1734 :   TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
     394        1734 :   return fds;
     395             : }
     396             : 
     397             : 
     398             : int
     399        1734 : _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
     400             : {
     401             :   int status;
     402             :   pid_t ret;
     403             : 
     404        1734 :   *r_status = 0;
     405        1734 :   *r_signal = 0;
     406             :   do
     407        1734 :     ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
     408        1724 :   while (ret == (pid_t)(-1) && errno == EINTR);
     409             : 
     410        1724 :   if (ret == pid)
     411             :     {
     412        1724 :       if (WIFSIGNALED (status))
     413             :         {
     414           0 :           *r_status = 4; /* Need some value here.  */
     415           0 :           *r_signal = WTERMSIG (status);
     416             :         }
     417        1724 :       else if (WIFEXITED (status))
     418        1724 :         *r_status = WEXITSTATUS (status);
     419             :       else
     420           0 :         *r_status = 4; /* Oops.  */
     421        1724 :       return 1;
     422             :     }
     423           0 :   return 0;
     424             : }
     425             : 
     426             : 
     427             : /* Returns 0 on success, -1 on error.  */
     428             : int
     429        1730 : _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
     430             :                  struct spawn_fd_item_s *fd_list,
     431             :                  void (*atfork) (void *opaque, int reserved),
     432             :                  void *atforkvalue, pid_t *r_pid)
     433             : {
     434             :   pid_t pid;
     435             :   int i;
     436             :   int status;
     437             :   int signo;
     438             : 
     439        1730 :   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
     440             :               "path=%s", path);
     441        1731 :   i = 0;
     442       21357 :   while (argv[i])
     443             :     {
     444       17895 :       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
     445       17895 :       i++;
     446             :     }
     447        4351 :   for (i = 0; fd_list[i].fd != -1; i++)
     448        2621 :     if (fd_list[i].dup_to == -1)
     449        1019 :       TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
     450             :     else
     451        1602 :       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
     452             : 
     453        1730 :   pid = fork ();
     454        3468 :   if (pid == -1)
     455           0 :     return TRACE_SYSRES (-1);
     456             : 
     457        3468 :   if (!pid)
     458             :     {
     459             :       /* Intermediate child to prevent zombie processes.  */
     460        1734 :       if ((pid = fork ()) == 0)
     461             :         {
     462             :           /* Child.  */
     463        1734 :           int max_fds = -1;
     464             :           int fd;
     465        1734 :           int seen_stdin = 0;
     466        1734 :           int seen_stdout = 0;
     467        1734 :           int seen_stderr = 0;
     468             : 
     469        1734 :           if (atfork)
     470           8 :             atfork (atforkvalue, 0);
     471             : 
     472             :           /* First close all fds which will not be inherited.  If we
     473             :            * have closefrom(2) we first figure out the highest fd we
     474             :            * do not want to close, then call closefrom, and on success
     475             :            * use the regular code to close all fds up to the start
     476             :            * point of closefrom.  Note that Solaris' closefrom does
     477             :            * not return errors.  */
     478             : #ifdef HAVE_CLOSEFROM
     479             :           {
     480             :             fd = -1;
     481             :             for (i = 0; fd_list[i].fd != -1; i++)
     482             :               if (fd_list[i].fd > fd)
     483             :                 fd = fd_list[i].fd;
     484             :             fd++;
     485             : #ifdef __sun
     486             :             closefrom (fd);
     487             :             max_fds = fd;
     488             : #else /*!__sun */
     489             :             while ((i = closefrom (fd)) && errno == EINTR)
     490             :               ;
     491             :             if (!i || errno == EBADF)
     492             :               max_fds = fd;
     493             : #endif /*!__sun*/
     494             :           }
     495             : #endif /*HAVE_CLOSEFROM*/
     496        1734 :           if (max_fds == -1)
     497        1734 :             max_fds = get_max_fds ();
     498     7104198 :           for (fd = 0; fd < max_fds; fd++)
     499             :             {
     500    17879206 :               for (i = 0; fd_list[i].fd != -1; i++)
     501    10779374 :                 if (fd_list[i].fd == fd)
     502        2632 :                   break;
     503     7102464 :               if (fd_list[i].fd == -1)
     504     7099832 :                 close (fd);
     505             :             }
     506             : 
     507             :           /* And now dup and close those to be duplicated.  */
     508        4366 :           for (i = 0; fd_list[i].fd != -1; i++)
     509             :             {
     510             :               int child_fd;
     511             :               int res;
     512             : 
     513        2632 :               if (fd_list[i].dup_to != -1)
     514        1606 :                 child_fd = fd_list[i].dup_to;
     515             :               else
     516        1026 :                 child_fd = fd_list[i].fd;
     517             : 
     518        2632 :               if (child_fd == 0)
     519          40 :                 seen_stdin = 1;
     520        2592 :               else if (child_fd == 1)
     521        1526 :                 seen_stdout = 1;
     522        1066 :               else if (child_fd == 2)
     523          40 :                 seen_stderr = 1;
     524             : 
     525        2632 :               if (fd_list[i].dup_to == -1)
     526        1026 :                 continue;
     527             : 
     528        1606 :               res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
     529        1606 :               if (res < 0)
     530             :                 {
     531             : #if 0
     532             :                   /* FIXME: The debug file descriptor is not
     533             :                      dup'ed anyway, so we can't see this.  */
     534             :                   TRACE_LOG1 ("dup2 failed in child: %s\n",
     535             :                               strerror (errno));
     536             : #endif
     537           0 :                   _exit (8);
     538             :                 }
     539             : 
     540        1606 :               close (fd_list[i].fd);
     541             :             }
     542             : 
     543        1734 :           if (! seen_stdin || ! seen_stdout || !seen_stderr)
     544             :             {
     545        1734 :               fd = open ("/dev/null", O_RDWR);
     546        1734 :               if (fd == -1)
     547             :                 {
     548             :                   /* The debug file descriptor is not dup'ed, so we
     549             :                      can't do a trace output.  */
     550           0 :                   _exit (8);
     551             :                 }
     552             :               /* Make sure that the process has connected stdin.  */
     553        1734 :               if (! seen_stdin && fd != 0)
     554             :                 {
     555           0 :                   if (dup2 (fd, 0) == -1)
     556           0 :                     _exit (8);
     557             :                 }
     558        1734 :               if (! seen_stdout && fd != 1)
     559             :                 {
     560         168 :                   if (dup2 (fd, 1) == -1)
     561           0 :                     _exit (8);
     562             :                 }
     563        1734 :               if (! seen_stderr && fd != 2)
     564             :                 {
     565        1694 :                   if (dup2 (fd, 2) == -1)
     566           0 :                     _exit (8);
     567             :                 }
     568        1734 :               if (fd != 0 && fd != 1 && fd != 2)
     569           0 :                 close (fd);
     570             :             }
     571             : 
     572        1734 :           execv (path, (char *const *) argv);
     573             :           /* Hmm: in that case we could write a special status code to the
     574             :              status-pipe.  */
     575        1734 :           _exit (8);
     576             :           /* End child.  */
     577             :         }
     578           0 :       if (pid == -1)
     579           0 :         _exit (1);
     580             :       else
     581           0 :         _exit (0);
     582             :     }
     583             : 
     584        1734 :   TRACE_LOG1 ("waiting for child process pid=%i", pid);
     585        1734 :   _gpgme_io_waitpid (pid, 1, &status, &signo);
     586        1724 :   if (status)
     587           0 :     return TRACE_SYSRES (-1);
     588             : 
     589        4333 :   for (i = 0; fd_list[i].fd != -1; i++)
     590             :     {
     591        2609 :       if (! (flags & IOSPAWN_FLAG_NOCLOSE))
     592        2601 :         _gpgme_io_close (fd_list[i].fd);
     593             :       /* No handle translation.  */
     594        2609 :       fd_list[i].peer_name = fd_list[i].fd;
     595             :     }
     596             : 
     597        1724 :   if (r_pid)
     598         653 :     *r_pid = pid;
     599             : 
     600        1724 :   return TRACE_SYSRES (0);
     601             : }
     602             : 
     603             : 
     604             : /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
     605             :    nothing to select, > 0 = number of signaled fds.  */
     606             : int
     607       12458 : _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
     608             : {
     609             :   fd_set readfds;
     610             :   fd_set writefds;
     611             :   unsigned int i;
     612             :   int any;
     613             :   int max_fd;
     614             :   int n;
     615             :   int count;
     616             :   /* Use a 1s timeout.  */
     617       12458 :   struct timeval timeout = { 1, 0 };
     618       12458 :   void *dbg_help = NULL;
     619       12458 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
     620             :               "nfds=%u, nonblock=%u", nfds, nonblock);
     621             : 
     622       12458 :   FD_ZERO (&readfds);
     623       12458 :   FD_ZERO (&writefds);
     624       12458 :   max_fd = 0;
     625       12458 :   if (nonblock)
     626        6512 :     timeout.tv_sec = 0;
     627             : 
     628       12458 :   TRACE_SEQ (dbg_help, "select on [ ");
     629             : 
     630       12458 :   any = 0;
     631       78430 :   for (i = 0; i < nfds; i++)
     632             :     {
     633       65972 :       if (fds[i].fd == -1)
     634       49346 :         continue;
     635       16626 :       if (fds[i].for_read)
     636             :         {
     637       14741 :           if (fds[i].fd >= FD_SETSIZE)
     638             :             {
     639           0 :               TRACE_END (dbg_help, " -BAD- ]");
     640           0 :               gpg_err_set_errno (EMFILE);
     641           0 :               return TRACE_SYSRES (-1);
     642             :             }
     643       14741 :           assert (!FD_ISSET (fds[i].fd, &readfds));
     644       14741 :           FD_SET (fds[i].fd, &readfds);
     645       14741 :           if (fds[i].fd > max_fd)
     646       14720 :             max_fd = fds[i].fd;
     647       14741 :           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
     648       14741 :           any = 1;
     649             :         }
     650        1885 :       else if (fds[i].for_write)
     651             :         {
     652        1885 :           if (fds[i].fd >= FD_SETSIZE)
     653             :             {
     654           0 :               TRACE_END (dbg_help, " -BAD- ]");
     655           0 :               gpg_err_set_errno (EMFILE);
     656           0 :               return TRACE_SYSRES (-1);
     657             :             }
     658        1885 :           assert (!FD_ISSET (fds[i].fd, &writefds));
     659        1885 :           FD_SET (fds[i].fd, &writefds);
     660        1885 :           if (fds[i].fd > max_fd)
     661        1800 :             max_fd = fds[i].fd;
     662        1885 :           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
     663        1885 :           any = 1;
     664             :         }
     665       16626 :       fds[i].signaled = 0;
     666             :     }
     667       12458 :   TRACE_END (dbg_help, "]");
     668       12458 :   if (!any)
     669         253 :     return TRACE_SYSRES (0);
     670             : 
     671             :   do
     672             :     {
     673       12205 :       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
     674             :                                  &timeout);
     675             :     }
     676       12210 :   while (count < 0 && errno == EINTR);
     677       12210 :   if (count < 0)
     678           0 :     return TRACE_SYSRES (-1);
     679             : 
     680       12210 :   TRACE_SEQ (dbg_help, "select OK [ ");
     681       12210 :   if (TRACE_ENABLED (dbg_help))
     682             :     {
     683           0 :       for (i = 0; i <= max_fd; i++)
     684             :         {
     685           0 :           if (FD_ISSET (i, &readfds))
     686           0 :             TRACE_ADD1 (dbg_help, "r0x%x ", i);
     687           0 :           if (FD_ISSET (i, &writefds))
     688           0 :             TRACE_ADD1 (dbg_help, "w0x%x ", i);
     689             :         }
     690           0 :       TRACE_END (dbg_help, "]");
     691             :     }
     692             : 
     693             :   /* The variable N is used to optimize it a little bit.  */
     694       27431 :   for (n = count, i = 0; i < nfds && n; i++)
     695             :     {
     696       15221 :       if (fds[i].fd == -1)
     697             :         ;
     698       14955 :       else if (fds[i].for_read)
     699             :         {
     700       13077 :           if (FD_ISSET (fds[i].fd, &readfds))
     701             :             {
     702       11146 :               fds[i].signaled = 1;
     703       11146 :               n--;
     704             :             }
     705             :         }
     706        1878 :       else if (fds[i].for_write)
     707             :         {
     708        1878 :           if (FD_ISSET (fds[i].fd, &writefds))
     709             :             {
     710        1878 :               fds[i].signaled = 1;
     711        1878 :               n--;
     712             :             }
     713             :         }
     714             :     }
     715       12210 :   return TRACE_SYSRES (count);
     716             : }
     717             : 
     718             : 
     719             : int
     720         123 : _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
     721             : {
     722             :   int nread;
     723             :   int saved_errno;
     724             :   struct iovec *iov;
     725         123 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
     726             :               "msg=%p, flags=%i", msg, flags);
     727             : 
     728         123 :   nread = 0;
     729         123 :   iov = msg->msg_iov;
     730         369 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     731             :     {
     732         123 :       nread += iov->iov_len;
     733         123 :       iov++;
     734             :     }
     735             : 
     736         123 :   TRACE_LOG1 ("about to receive %d bytes", nread);
     737             : 
     738             :   do
     739             :     {
     740         123 :       nread = _gpgme_ath_recvmsg (fd, msg, flags);
     741             :     }
     742         123 :   while (nread == -1 && errno == EINTR);
     743         123 :   saved_errno = errno;
     744         123 :   if (nread > 0)
     745             :     {
     746         123 :       int nr = nread;
     747             : 
     748         123 :       iov = msg->msg_iov;
     749         369 :       while (nr > 0)
     750             :         {
     751         123 :           int len = nr > iov->iov_len ? iov->iov_len : nr;
     752         123 :           TRACE_LOGBUF (msg->msg_iov->iov_base, len);
     753         123 :           iov++;
     754         123 :           nr -= len;
     755             :         }
     756             :     }
     757         123 :   errno = saved_errno;
     758         123 :   return TRACE_SYSRES (nread);
     759             : }
     760             : 
     761             : 
     762             : int
     763         240 : _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
     764             : {
     765             :   int nwritten;
     766             :   struct iovec *iov;
     767         240 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
     768             :               "msg=%p, flags=%i", msg, flags);
     769             : 
     770         240 :   nwritten = 0;
     771         240 :   iov = msg->msg_iov;
     772         720 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     773             :     {
     774         240 :       nwritten += iov->iov_len;
     775         240 :       iov++;
     776             :     }
     777             : 
     778         240 :   TRACE_LOG1 ("about to receive %d bytes", nwritten);
     779         240 :   iov = msg->msg_iov;
     780         720 :   while (nwritten > 0)
     781             :     {
     782         240 :       int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
     783         240 :       TRACE_LOGBUF (msg->msg_iov->iov_base, len);
     784         240 :       iov++;
     785         240 :       nwritten -= len;
     786             :     }
     787             : 
     788             :   do
     789             :     {
     790         240 :       nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
     791             :     }
     792         240 :   while (nwritten == -1 && errno == EINTR);
     793         240 :   return TRACE_SYSRES (nwritten);
     794             : }
     795             : 
     796             : 
     797             : int
     798          40 : _gpgme_io_dup (int fd)
     799             : {
     800             :   int new_fd;
     801             : 
     802             :   do
     803          40 :     new_fd = dup (fd);
     804          40 :   while (new_fd == -1 && errno == EINTR);
     805             : 
     806          40 :   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
     807             : 
     808          40 :   return new_fd;
     809             : }
     810             : 
     811             : 
     812             : int
     813          12 : _gpgme_io_socket (int domain, int type, int proto)
     814             : {
     815             :   int res;
     816             : 
     817          12 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
     818             :               "type=%i, proto=%i", type, proto);
     819             : 
     820          12 :   res = socket (domain, type, proto);
     821             : 
     822          12 :   return TRACE_SYSRES (res);
     823             : }
     824             : 
     825             : 
     826             : int
     827          12 : _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
     828             : {
     829             :   int res;
     830             : 
     831          12 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
     832             :               "addr=%p, addrlen=%i", addr, addrlen);
     833             : 
     834             :   do
     835          12 :     res = ath_connect (fd, addr, addrlen);
     836          12 :   while (res == -1 && errno == EINTR);
     837             : 
     838          12 :   return TRACE_SYSRES (res);
     839             : }

Generated by: LCOV version 1.13