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