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