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 : }
|