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