LCOV - code coverage report
Current view: top level - src - posix-io.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 290 346 83.8 %
Date: 2018-11-15 08:49:49 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             : #ifdef USE_LINUX_GETDENTS
      51             : # include <sys/syscall.h>
      52             : # include <sys/types.h>
      53             : # include <dirent.h>
      54             : #endif /*USE_LINUX_GETDENTS*/
      55             : 
      56             : 
      57             : #include "util.h"
      58             : #include "priv-io.h"
      59             : #include "sema.h"
      60             : #include "ath.h"
      61             : #include "debug.h"
      62             : 
      63             : 
      64             : 
      65             : void
      66         119 : _gpgme_io_subsystem_init (void)
      67             : {
      68             :   struct sigaction act;
      69             : 
      70         119 :   sigaction (SIGPIPE, NULL, &act);
      71         119 :   if (act.sa_handler == SIG_DFL)
      72             :     {
      73          35 :       act.sa_handler = SIG_IGN;
      74          35 :       sigemptyset (&act.sa_mask);
      75          35 :       act.sa_flags = 0;
      76          35 :       sigaction (SIGPIPE, &act, NULL);
      77             :     }
      78         119 : }
      79             : 
      80             : 
      81             : /* Write the printable version of FD to the buffer BUF of length
      82             :    BUFLEN.  The printable version is the representation on the command
      83             :    line that the child process expects.  */
      84             : int
      85        1885 : _gpgme_io_fd2str (char *buf, int buflen, int fd)
      86             : {
      87        1885 :   return snprintf (buf, buflen, "%d", fd);
      88             : }
      89             : 
      90             : 
      91             : /* The table to hold notification handlers.  We use a linear search
      92             :    and extend the table as needed.  */
      93             : struct notify_table_item_s
      94             : {
      95             :   int fd;  /* -1 indicates an unused entry.  */
      96             :   _gpgme_close_notify_handler_t handler;
      97             :   void *value;
      98             : };
      99             : typedef struct notify_table_item_s *notify_table_item_t;
     100             : 
     101             : static notify_table_item_t notify_table;
     102             : static size_t notify_table_size;
     103             : DEFINE_STATIC_LOCK (notify_table_lock);
     104             : 
     105             : 
     106             : 
     107             : int
     108       10709 : _gpgme_io_read (int fd, void *buffer, size_t count)
     109             : {
     110             :   int nread;
     111       10709 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
     112             :               "buffer=%p, count=%u", buffer, count);
     113             : 
     114             :   do
     115             :     {
     116       10706 :       nread = _gpgme_ath_read (fd, buffer, count);
     117             :     }
     118       10705 :   while (nread == -1 && errno == EINTR);
     119             : 
     120       10705 :   TRACE_LOGBUFX (buffer, nread);
     121       10704 :   return TRACE_SYSRES (nread);
     122             : }
     123             : 
     124             : 
     125             : int
     126         766 : _gpgme_io_write (int fd, const void *buffer, size_t count)
     127             : {
     128             :   int nwritten;
     129         766 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
     130             :               "buffer=%p, count=%u", buffer, count);
     131         766 :   TRACE_LOGBUFX (buffer, count);
     132             : 
     133             :   do
     134             :     {
     135         766 :       nwritten = _gpgme_ath_write (fd, buffer, count);
     136             :     }
     137         766 :   while (nwritten == -1 && errno == EINTR);
     138             : 
     139         766 :   return TRACE_SYSRES (nwritten);
     140             : }
     141             : 
     142             : 
     143             : int
     144        3948 : _gpgme_io_pipe (int filedes[2], int inherit_idx)
     145             : {
     146             :   int saved_errno;
     147             :   int err;
     148        3948 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
     149             :               "inherit_idx=%i (GPGME uses it for %s)",
     150             :               inherit_idx, inherit_idx ? "reading" : "writing");
     151             : 
     152        3947 :   err = pipe (filedes);
     153        3942 :   if (err < 0)
     154           0 :     return TRACE_SYSRES (err);
     155             : 
     156             :   /* FIXME: Should get the old flags first.  */
     157        3942 :   err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
     158        3945 :   saved_errno = errno;
     159        3944 :   if (err < 0)
     160             :     {
     161           0 :       close (filedes[0]);
     162           0 :       close (filedes[1]);
     163             :     }
     164        3944 :   errno = saved_errno;
     165        3945 :   if (err)
     166           0 :     return TRACE_SYSRES (err);
     167             : 
     168        3945 :   return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
     169             : }
     170             : 
     171             : 
     172             : int
     173        7867 : _gpgme_io_close (int fd)
     174             : {
     175             :   int res;
     176        7867 :   _gpgme_close_notify_handler_t handler = NULL;
     177             :   void *handler_value;
     178             :   int idx;
     179             : 
     180        7867 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
     181             : 
     182        7867 :   if (fd == -1)
     183             :     {
     184           0 :       errno = EINVAL;
     185           0 :       return TRACE_SYSRES (-1);
     186             :     }
     187             : 
     188             :   /* First call the notify handler.  */
     189        7867 :   LOCK (notify_table_lock);
     190       68292 :   for (idx=0; idx < notify_table_size; idx++)
     191             :     {
     192       65429 :       if (notify_table[idx].fd == fd)
     193             :         {
     194        5004 :           handler       = notify_table[idx].handler;
     195        5004 :           handler_value = notify_table[idx].value;
     196        5004 :           notify_table[idx].handler = NULL;
     197        5004 :           notify_table[idx].value = NULL;
     198        5004 :           notify_table[idx].fd = -1; /* Mark slot as free.  */
     199        5004 :           break;
     200             :         }
     201             :     }
     202        7867 :   UNLOCK (notify_table_lock);
     203        7866 :   if (handler)
     204             :     {
     205        5003 :       TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
     206        5003 :       handler (fd, handler_value);
     207             :     }
     208             : 
     209             :   /* Then do the close.  */
     210        7866 :   res = close (fd);
     211        7866 :   return TRACE_SYSRES (res);
     212             : }
     213             : 
     214             : 
     215             : int
     216        5084 : _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
     217             :                             void *value)
     218             : {
     219        5084 :   int res = 0;
     220             :   int idx;
     221             : 
     222        5084 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
     223             :               "close_handler=%p/%p", handler, value);
     224             : 
     225        5079 :   assert (fd != -1);
     226             : 
     227        5079 :   LOCK (notify_table_lock);
     228       30055 :   for (idx=0; idx < notify_table_size; idx++)
     229       29949 :     if (notify_table[idx].fd == -1)
     230        4982 :       break;
     231        5088 :   if (idx == notify_table_size)
     232             :     {
     233             :       /* We need to increase the size of the table.  The approach we
     234             :          take is straightforward to minimize the risk of bugs.  */
     235             :       notify_table_item_t newtbl;
     236         106 :       size_t newsize = notify_table_size + 64;
     237             : 
     238         106 :       newtbl = calloc (newsize, sizeof *newtbl);
     239         106 :       if (!newtbl)
     240             :         {
     241           0 :           res = -1;
     242           0 :           goto leave;
     243             :         }
     244         170 :       for (idx=0; idx < notify_table_size; idx++)
     245          64 :         newtbl[idx] = notify_table[idx];
     246        6890 :       for (; idx < newsize; idx++)
     247             :         {
     248        6784 :           newtbl[idx].fd = -1;
     249        6784 :           newtbl[idx].handler = NULL;
     250        6784 :           newtbl[idx].value = NULL;
     251             :         }
     252         106 :       free (notify_table);
     253         106 :       notify_table = newtbl;
     254         106 :       idx = notify_table_size;
     255         106 :       notify_table_size = newsize;
     256             :     }
     257        5088 :   notify_table[idx].fd = fd;
     258        5088 :   notify_table[idx].handler = handler;
     259        5088 :   notify_table[idx].value = value;
     260             : 
     261             :  leave:
     262        5088 :   UNLOCK (notify_table_lock);
     263             : 
     264        5088 :   return TRACE_SYSRES (res);
     265             : }
     266             : 
     267             : 
     268             : int
     269         393 : _gpgme_io_set_nonblocking (int fd)
     270             : {
     271             :   int flags;
     272             :   int res;
     273         393 :   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
     274             : 
     275         393 :   flags = fcntl (fd, F_GETFL, 0);
     276         393 :   if (flags == -1)
     277           0 :     return TRACE_SYSRES (-1);
     278         393 :   flags |= O_NONBLOCK;
     279         393 :   res = fcntl (fd, F_SETFL, flags);
     280         393 :   return TRACE_SYSRES (res);
     281             : }
     282             : 
     283             : 
     284             : #ifdef USE_LINUX_GETDENTS
     285             : /* This is not declared in public headers; getdents64(2) says that we must
     286             :  * define it ourselves.  */
     287             : struct linux_dirent64
     288             : {
     289             :   ino64_t d_ino;
     290             :   off64_t d_off;
     291             :   unsigned short d_reclen;
     292             :   unsigned char d_type;
     293             :   char d_name[];
     294             : };
     295             : 
     296             : # define DIR_BUF_SIZE 1024
     297             : #endif /*USE_LINUX_GETDENTS*/
     298             : 
     299             : 
     300             : static long int
     301        2146 : get_max_fds (void)
     302             : {
     303        2146 :   const char *source = NULL;
     304        2146 :   long int fds = -1;
     305             :   int rc;
     306             : 
     307             :   /* Under Linux we can figure out the highest used file descriptor by
     308             :    * reading /proc/self/fd.  This is in the common cases much faster
     309             :    * than for example doing 4096 close calls where almost all of them
     310             :    * will fail.
     311             :    *
     312             :    * We can't use the normal opendir/readdir/closedir interface between
     313             :    * fork and exec in a multi-threaded process because opendir uses
     314             :    * malloc and thus a mutex which may deadlock with a malloc in another
     315             :    * thread.  However, the underlying getdents system call is safe.  */
     316             : #ifdef USE_LINUX_GETDENTS
     317             :   {
     318             :     int dir_fd;
     319             :     char dir_buf[DIR_BUF_SIZE];
     320             :     struct linux_dirent64 *dir_entry;
     321             :     int r, pos;
     322             :     const char *s;
     323             :     int x;
     324             : 
     325        2146 :     dir_fd = open ("/proc/self/fd", O_RDONLY | O_DIRECTORY);
     326        2146 :     if (dir_fd != -1)
     327             :       {
     328             :         for (;;)
     329             :           {
     330        6526 :             r = syscall(SYS_getdents64, dir_fd, dir_buf, DIR_BUF_SIZE);
     331        4336 :             if (r == -1)
     332             :               {
     333             :                 /* Fall back to other methods.  */
     334           0 :                 fds = -1;
     335           0 :                 break;
     336             :               }
     337        4336 :             if (r == 0)
     338        2146 :               break;
     339             : 
     340       27177 :             for (pos = 0; pos < r; pos += dir_entry->d_reclen)
     341             :               {
     342       24987 :                 dir_entry = (struct linux_dirent64 *) (dir_buf + pos);
     343       24987 :                 s = dir_entry->d_name;
     344       24987 :                 if (*s < '0' || *s > '9')
     345        4292 :                   continue;
     346             :                 /* atoi is not guaranteed to be async-signal-safe.  */
     347       45860 :                 for (x = 0; *s >= '0' && *s <= '9'; s++)
     348       25165 :                   x = x * 10 + (*s - '0');
     349       20695 :                 if (!*s && x > fds && x != dir_fd)
     350       18549 :                   fds = x;
     351             :               }
     352             :           }
     353             : 
     354        2146 :         close (dir_fd);
     355             :       }
     356        2146 :     if (fds != -1)
     357             :       {
     358        2146 :         fds++;
     359        2146 :         source = "/proc";
     360             :       }
     361             :     }
     362             : #endif /*USE_LINUX_GETDENTS*/
     363             : 
     364             : #ifdef RLIMIT_NOFILE
     365        2146 :   if (fds == -1)
     366             :     {
     367             :       struct rlimit rl;
     368           0 :       rc = getrlimit (RLIMIT_NOFILE, &rl);
     369           0 :       if (rc == 0)
     370             :         {
     371           0 :           source = "RLIMIT_NOFILE";
     372           0 :           fds = rl.rlim_max;
     373             :         }
     374             :     }
     375             : #endif
     376             : #ifdef RLIMIT_OFILE
     377        2146 :   if (fds == -1)
     378             :     {
     379             :       struct rlimit rl;
     380           0 :       rc = getrlimit (RLIMIT_OFILE, &rl);
     381           0 :       if (rc == 0)
     382             :         {
     383           0 :           source = "RLIMIT_OFILE";
     384           0 :           fds = rl.rlim_max;
     385             :         }
     386             :     }
     387             : #endif
     388             : #ifdef _SC_OPEN_MAX
     389        2146 :   if (fds == -1)
     390             :     {
     391             :       long int scres;
     392           0 :       scres = sysconf (_SC_OPEN_MAX);
     393           0 :       if (scres >= 0)
     394             :         {
     395           0 :           source = "_SC_OPEN_MAX";
     396           0 :           return scres;
     397             :         }
     398             :     }
     399             : #endif
     400             : #ifdef OPEN_MAX
     401             :   if (fds == -1)
     402             :     {
     403             :       source = "OPEN_MAX";
     404             :       fds = OPEN_MAX;
     405             :     }
     406             : #endif
     407             : 
     408             : #if !defined(RLIMIT_NOFILE) && !defined(RLIMIT_OFILE) \
     409             :   && !defined(_SC_OPEN_MAX) && !defined(OPEN_MAX)
     410             : #warning "No known way to get the maximum number of file descriptors."
     411             : #endif
     412        2146 :   if (fds == -1)
     413             :     {
     414           0 :       source = "arbitrary";
     415             :       /* Arbitrary limit.  */
     416           0 :       fds = 1024;
     417             :     }
     418             : 
     419             :   /* AIX returns INT32_MAX instead of a proper value.  We assume that
     420             :    * this is always an error and use a more reasonable limit.  */
     421             : #ifdef INT32_MAX
     422        2146 :   if (fds == INT32_MAX)
     423             :     {
     424           0 :       source = "aix-fix";
     425           0 :       fds = 1024;
     426             :     }
     427             : #endif
     428             : 
     429        2146 :   TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
     430        2146 :   return fds;
     431             : }
     432             : 
     433             : 
     434             : int
     435        2146 : _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
     436             : {
     437             :   int status;
     438             :   pid_t ret;
     439             : 
     440        2146 :   *r_status = 0;
     441        2146 :   *r_signal = 0;
     442             :   do
     443        2146 :     ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
     444        2126 :   while (ret == (pid_t)(-1) && errno == EINTR);
     445             : 
     446        2126 :   if (ret == pid)
     447             :     {
     448        2126 :       if (WIFSIGNALED (status))
     449             :         {
     450           0 :           *r_status = 4; /* Need some value here.  */
     451           0 :           *r_signal = WTERMSIG (status);
     452             :         }
     453        2126 :       else if (WIFEXITED (status))
     454        2126 :         *r_status = WEXITSTATUS (status);
     455             :       else
     456           0 :         *r_status = 4; /* Oops.  */
     457        2126 :       return 1;
     458             :     }
     459           0 :   return 0;
     460             : }
     461             : 
     462             : 
     463             : /* Returns 0 on success, -1 on error.  */
     464             : int
     465        2136 : _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
     466             :                  struct spawn_fd_item_s *fd_list,
     467             :                  void (*atfork) (void *opaque, int reserved),
     468             :                  void *atforkvalue, pid_t *r_pid)
     469             : {
     470             :   pid_t pid;
     471             :   int i;
     472             :   int status;
     473             :   int signo;
     474             : 
     475        2136 :   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
     476             :               "path=%s", path);
     477        2136 :   i = 0;
     478       26424 :   while (argv[i])
     479             :     {
     480       22152 :       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
     481       22152 :       i++;
     482             :     }
     483        6058 :   for (i = 0; fd_list[i].fd != -1; i++)
     484        3922 :     if (fd_list[i].dup_to == -1)
     485        1883 :       TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
     486             :     else
     487        2039 :       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
     488             : 
     489        2136 :   pid = fork ();
     490        4292 :   if (pid == -1)
     491           0 :     return TRACE_SYSRES (-1);
     492             : 
     493        4292 :   if (!pid)
     494             :     {
     495             :       /* Intermediate child to prevent zombie processes.  */
     496        2146 :       if ((pid = fork ()) == 0)
     497             :         {
     498             :           /* Child.  */
     499        2146 :           int max_fds = -1;
     500             :           int fd;
     501        2146 :           int seen_stdin = 0;
     502        2146 :           int seen_stdout = 0;
     503        2146 :           int seen_stderr = 0;
     504             : 
     505        2146 :           if (atfork)
     506           8 :             atfork (atforkvalue, 0);
     507             : 
     508             :           /* First close all fds which will not be inherited.  If we
     509             :            * have closefrom(2) we first figure out the highest fd we
     510             :            * do not want to close, then call closefrom, and on success
     511             :            * use the regular code to close all fds up to the start
     512             :            * point of closefrom.  Note that Solaris' and FreeBSD's closefrom do
     513             :            * not return errors.  */
     514             : #ifdef HAVE_CLOSEFROM
     515             :           {
     516             :             fd = -1;
     517             :             for (i = 0; fd_list[i].fd != -1; i++)
     518             :               if (fd_list[i].fd > fd)
     519             :                 fd = fd_list[i].fd;
     520             :             fd++;
     521             : #if defined(__sun) || defined(__FreeBSD__)
     522             :             closefrom (fd);
     523             :             max_fds = fd;
     524             : #else /*!__sun */
     525             :             while ((i = closefrom (fd)) && errno == EINTR)
     526             :               ;
     527             :             if (!i || errno == EBADF)
     528             :               max_fds = fd;
     529             : #endif /*!__sun*/
     530             :           }
     531             : #endif /*HAVE_CLOSEFROM*/
     532        2146 :           if (max_fds == -1)
     533        2146 :             max_fds = get_max_fds ();
     534       22240 :           for (fd = 0; fd < max_fds; fd++)
     535             :             {
     536       61266 :               for (i = 0; fd_list[i].fd != -1; i++)
     537       45126 :                 if (fd_list[i].fd == fd)
     538        3954 :                   break;
     539       20094 :               if (fd_list[i].fd == -1)
     540       16140 :                 close (fd);
     541             :             }
     542             : 
     543             :           /* And now dup and close those to be duplicated.  */
     544        6100 :           for (i = 0; fd_list[i].fd != -1; i++)
     545             :             {
     546             :               int child_fd;
     547             :               int res;
     548             : 
     549        3954 :               if (fd_list[i].dup_to != -1)
     550        2045 :                 child_fd = fd_list[i].dup_to;
     551             :               else
     552        1909 :                 child_fd = fd_list[i].fd;
     553             : 
     554        3954 :               if (child_fd == 0)
     555          60 :                 seen_stdin = 1;
     556        3894 :               else if (child_fd == 1)
     557        1925 :                 seen_stdout = 1;
     558        1969 :               else if (child_fd == 2)
     559          60 :                 seen_stderr = 1;
     560             : 
     561        3954 :               if (fd_list[i].dup_to == -1)
     562        1909 :                 continue;
     563             : 
     564        2045 :               res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
     565        2045 :               if (res < 0)
     566             :                 {
     567             : #if 0
     568             :                   /* FIXME: The debug file descriptor is not
     569             :                      dup'ed anyway, so we can't see this.  */
     570             :                   TRACE_LOG1 ("dup2 failed in child: %s\n",
     571             :                               strerror (errno));
     572             : #endif
     573           0 :                   _exit (8);
     574             :                 }
     575             : 
     576        2045 :               close (fd_list[i].fd);
     577             :             }
     578             : 
     579        2146 :           if (! seen_stdin || ! seen_stdout || !seen_stderr)
     580             :             {
     581        2128 :               fd = open ("/dev/null", O_RDWR);
     582        2128 :               if (fd == -1)
     583             :                 {
     584             :                   /* The debug file descriptor is not dup'ed, so we
     585             :                      can't do a trace output.  */
     586           0 :                   _exit (8);
     587             :                 }
     588             :               /* Make sure that the process has connected stdin.  */
     589        2128 :               if (! seen_stdin && fd != 0)
     590             :                 {
     591           0 :                   if (dup2 (fd, 0) == -1)
     592           0 :                     _exit (8);
     593             :                 }
     594        2128 :               if (! seen_stdout && fd != 1)
     595             :                 {
     596         179 :                   if (dup2 (fd, 1) == -1)
     597           0 :                     _exit (8);
     598             :                 }
     599        2128 :               if (! seen_stderr && fd != 2)
     600             :                 {
     601        2086 :                   if (dup2 (fd, 2) == -1)
     602           0 :                     _exit (8);
     603             :                 }
     604        2128 :               if (fd != 0 && fd != 1 && fd != 2)
     605           0 :                 close (fd);
     606             :             }
     607             : 
     608        2146 :           execv (path, (char *const *) argv);
     609             :           /* Hmm: in that case we could write a special status code to the
     610             :              status-pipe.  */
     611        2146 :           _exit (8);
     612             :           /* End child.  */
     613             :         }
     614           0 :       if (pid == -1)
     615           0 :         _exit (1);
     616             :       else
     617           0 :         _exit (0);
     618             :     }
     619             : 
     620        2146 :   TRACE_LOG1 ("waiting for child process pid=%i", pid);
     621        2146 :   _gpgme_io_waitpid (pid, 1, &status, &signo);
     622        2126 :   if (status)
     623           0 :     return TRACE_SYSRES (-1);
     624             : 
     625        6007 :   for (i = 0; fd_list[i].fd != -1; i++)
     626             :     {
     627        3882 :       if (! (flags & IOSPAWN_FLAG_NOCLOSE))
     628        3874 :         _gpgme_io_close (fd_list[i].fd);
     629             :       /* No handle translation.  */
     630        3881 :       fd_list[i].peer_name = fd_list[i].fd;
     631             :     }
     632             : 
     633        2125 :   if (r_pid)
     634         759 :     *r_pid = pid;
     635             : 
     636        2125 :   return TRACE_SYSRES (0);
     637             : }
     638             : 
     639             : 
     640             : /* Select on the list of fds.  Returns: -1 = error, 0 = timeout or
     641             :    nothing to select, > 0 = number of signaled fds.  */
     642             : int
     643       17881 : _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
     644             : {
     645             :   fd_set readfds;
     646             :   fd_set writefds;
     647             :   unsigned int i;
     648             :   int any;
     649             :   int max_fd;
     650             :   int n;
     651             :   int count;
     652             :   /* Use a 1s timeout.  */
     653       17881 :   struct timeval timeout = { 1, 0 };
     654       17881 :   void *dbg_help = NULL;
     655       17881 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
     656             :               "nfds=%u, nonblock=%u", nfds, nonblock);
     657             : 
     658       17880 :   FD_ZERO (&readfds);
     659       17880 :   FD_ZERO (&writefds);
     660       17883 :   max_fd = 0;
     661       17883 :   if (nonblock)
     662        9638 :     timeout.tv_sec = 0;
     663             : 
     664       17883 :   TRACE_SEQ (dbg_help, "select on [ ");
     665             : 
     666       17879 :   any = 0;
     667      109939 :   for (i = 0; i < nfds; i++)
     668             :     {
     669       92058 :       if (fds[i].fd == -1)
     670       60670 :         continue;
     671       31388 :       if (fds[i].for_read)
     672             :         {
     673       25082 :           if (fds[i].fd >= FD_SETSIZE)
     674             :             {
     675           0 :               TRACE_END (dbg_help, " -BAD- ]");
     676           0 :               gpg_err_set_errno (EMFILE);
     677           0 :               return TRACE_SYSRES (-1);
     678             :             }
     679       29333 :           assert (!FD_ISSET (fds[i].fd, &readfds));
     680       29333 :           FD_SET (fds[i].fd, &readfds);
     681       29333 :           if (fds[i].fd > max_fd)
     682       29296 :             max_fd = fds[i].fd;
     683       29333 :           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
     684       25084 :           any = 1;
     685             :         }
     686        6306 :       else if (fds[i].for_write)
     687             :         {
     688        2061 :           if (fds[i].fd >= FD_SETSIZE)
     689             :             {
     690           0 :               TRACE_END (dbg_help, " -BAD- ]");
     691           0 :               gpg_err_set_errno (EMFILE);
     692           0 :               return TRACE_SYSRES (-1);
     693             :             }
     694        2061 :           assert (!FD_ISSET (fds[i].fd, &writefds));
     695        2061 :           FD_SET (fds[i].fd, &writefds);
     696        2061 :           if (fds[i].fd > max_fd)
     697        1975 :             max_fd = fds[i].fd;
     698        2061 :           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
     699        2061 :           any = 1;
     700             :         }
     701       31390 :       fds[i].signaled = 0;
     702             :     }
     703       17881 :   TRACE_END (dbg_help, "]");
     704       17879 :   if (!any)
     705         343 :     return TRACE_SYSRES (0);
     706             : 
     707             :   do
     708             :     {
     709       17536 :       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
     710             :                                  &timeout);
     711             :     }
     712       17564 :   while (count < 0 && errno == EINTR);
     713       17564 :   if (count < 0)
     714           0 :     return TRACE_SYSRES (-1);
     715             : 
     716       17564 :   TRACE_SEQ (dbg_help, "select OK [ ");
     717       17565 :   if (TRACE_ENABLED (dbg_help))
     718             :     {
     719           0 :       for (i = 0; i <= max_fd; i++)
     720             :         {
     721           0 :           if (FD_ISSET (i, &readfds))
     722           0 :             TRACE_ADD1 (dbg_help, "r0x%x ", i);
     723           0 :           if (FD_ISSET (i, &writefds))
     724           0 :             TRACE_ADD1 (dbg_help, "w0x%x ", i);
     725             :         }
     726           0 :       TRACE_END (dbg_help, "]");
     727             :     }
     728             : 
     729             :   /* The variable N is used to optimize it a little bit.  */
     730       41795 :   for (n = count, i = 0; i < nfds && n; i++)
     731             :     {
     732       24233 :       if (fds[i].fd == -1)
     733             :         ;
     734       23918 :       else if (fds[i].for_read)
     735             :         {
     736       21864 :           if (FD_ISSET (fds[i].fd, &readfds))
     737             :             {
     738       17240 :               fds[i].signaled = 1;
     739       17240 :               n--;
     740             :             }
     741             :         }
     742        2054 :       else if (fds[i].for_write)
     743             :         {
     744        2054 :           if (FD_ISSET (fds[i].fd, &writefds))
     745             :             {
     746        2054 :               fds[i].signaled = 1;
     747        2054 :               n--;
     748             :             }
     749             :         }
     750             :     }
     751       17562 :   return TRACE_SYSRES (count);
     752             : }
     753             : 
     754             : 
     755             : int
     756         127 : _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
     757             : {
     758             :   int nread;
     759             :   int saved_errno;
     760             :   struct iovec *iov;
     761         127 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
     762             :               "msg=%p, flags=%i", msg, flags);
     763             : 
     764         127 :   nread = 0;
     765         127 :   iov = msg->msg_iov;
     766         381 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     767             :     {
     768         127 :       nread += iov->iov_len;
     769         127 :       iov++;
     770             :     }
     771             : 
     772         127 :   TRACE_LOG1 ("about to receive %d bytes", nread);
     773             : 
     774             :   do
     775             :     {
     776         127 :       nread = _gpgme_ath_recvmsg (fd, msg, flags);
     777             :     }
     778         127 :   while (nread == -1 && errno == EINTR);
     779         127 :   saved_errno = errno;
     780         127 :   if (nread > 0)
     781             :     {
     782         127 :       int nr = nread;
     783             : 
     784         127 :       iov = msg->msg_iov;
     785         381 :       while (nr > 0)
     786             :         {
     787         127 :           int len = nr > iov->iov_len ? iov->iov_len : nr;
     788         127 :           TRACE_LOGBUFX (msg->msg_iov->iov_base, len);
     789         127 :           iov++;
     790         127 :           nr -= len;
     791             :         }
     792             :     }
     793         127 :   errno = saved_errno;
     794         127 :   return TRACE_SYSRES (nread);
     795             : }
     796             : 
     797             : 
     798             : int
     799         240 : _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
     800             : {
     801             :   int nwritten;
     802             :   struct iovec *iov;
     803         240 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
     804             :               "msg=%p, flags=%i", msg, flags);
     805             : 
     806         240 :   nwritten = 0;
     807         240 :   iov = msg->msg_iov;
     808         720 :   while (iov < msg->msg_iov + msg->msg_iovlen)
     809             :     {
     810         240 :       nwritten += iov->iov_len;
     811         240 :       iov++;
     812             :     }
     813             : 
     814         240 :   TRACE_LOG1 ("about to receive %d bytes", nwritten);
     815         240 :   iov = msg->msg_iov;
     816         720 :   while (nwritten > 0)
     817             :     {
     818         240 :       int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
     819         240 :       TRACE_LOGBUFX (msg->msg_iov->iov_base, len);
     820         240 :       iov++;
     821         240 :       nwritten -= len;
     822             :     }
     823             : 
     824             :   do
     825             :     {
     826         240 :       nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
     827             :     }
     828         240 :   while (nwritten == -1 && errno == EINTR);
     829         240 :   return TRACE_SYSRES (nwritten);
     830             : }
     831             : 
     832             : 
     833             : int
     834          30 : _gpgme_io_dup (int fd)
     835             : {
     836             :   int new_fd;
     837             : 
     838             :   do
     839          30 :     new_fd = dup (fd);
     840          30 :   while (new_fd == -1 && errno == EINTR);
     841             : 
     842          30 :   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
     843             : 
     844          30 :   return new_fd;
     845             : }
     846             : 
     847             : 
     848             : int
     849          14 : _gpgme_io_socket (int domain, int type, int proto)
     850             : {
     851             :   int res;
     852             : 
     853          14 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
     854             :               "type=%i, proto=%i", type, proto);
     855             : 
     856          14 :   res = socket (domain, type, proto);
     857             : 
     858          14 :   return TRACE_SYSRES (res);
     859             : }
     860             : 
     861             : 
     862             : int
     863          14 : _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
     864             : {
     865             :   int res;
     866             : 
     867          14 :   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
     868             :               "addr=%p, addrlen=%i", addr, addrlen);
     869             : 
     870             :   do
     871          14 :     res = ath_connect (fd, addr, addrlen);
     872          14 :   while (res == -1 && errno == EINTR);
     873             : 
     874          14 :   return TRACE_SYSRES (res);
     875             : }

Generated by: LCOV version 1.13