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 <http://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 : #include <string.h>
27 : #include <assert.h>
28 : #include <errno.h>
29 : #include <signal.h>
30 : #include <fcntl.h>
31 : #ifdef HAVE_UNISTD_H
32 : # include <unistd.h>
33 : #endif
34 : #ifdef HAVE_SYS_TIME_H
35 : # include <sys/time.h>
36 : #endif
37 : #ifdef HAVE_SYS_TYPES_H
38 : # include <sys/types.h>
39 : #endif
40 : #include <sys/wait.h>
41 : #ifdef HAVE_SYS_UIO_H
42 : # include <sys/uio.h>
43 : #endif
44 : #include <ctype.h>
45 : #include <sys/resource.h>
46 :
47 : #include "util.h"
48 : #include "priv-io.h"
49 : #include "sema.h"
50 : #include "ath.h"
51 : #include "debug.h"
52 :
53 :
54 : void
55 29 : _gpgme_io_subsystem_init (void)
56 : {
57 : struct sigaction act;
58 :
59 29 : sigaction (SIGPIPE, NULL, &act);
60 29 : if (act.sa_handler == SIG_DFL)
61 : {
62 29 : act.sa_handler = SIG_IGN;
63 29 : sigemptyset (&act.sa_mask);
64 29 : act.sa_flags = 0;
65 29 : sigaction (SIGPIPE, &act, NULL);
66 : }
67 29 : }
68 :
69 :
70 : /* Write the printable version of FD to the buffer BUF of length
71 : BUFLEN. The printable version is the representation on the command
72 : line that the child process expects. */
73 : int
74 226 : _gpgme_io_fd2str (char *buf, int buflen, int fd)
75 : {
76 226 : return snprintf (buf, buflen, "%d", fd);
77 : }
78 :
79 :
80 : /* The table to hold notification handlers. We use a linear search
81 : and extend the table as needed. */
82 : struct notify_table_item_s
83 : {
84 : int fd; /* -1 indicates an unused entry. */
85 : _gpgme_close_notify_handler_t handler;
86 : void *value;
87 : };
88 : typedef struct notify_table_item_s *notify_table_item_t;
89 :
90 : static notify_table_item_t notify_table;
91 : static size_t notify_table_size;
92 : DEFINE_STATIC_LOCK (notify_table_lock);
93 :
94 :
95 :
96 : int
97 1005 : _gpgme_io_read (int fd, void *buffer, size_t count)
98 : {
99 : int nread;
100 1005 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
101 : "buffer=%p, count=%u", buffer, count);
102 :
103 : do
104 : {
105 1005 : nread = _gpgme_ath_read (fd, buffer, count);
106 : }
107 1005 : while (nread == -1 && errno == EINTR);
108 :
109 1005 : TRACE_LOGBUF (buffer, nread);
110 1005 : return TRACE_SYSRES (nread);
111 : }
112 :
113 :
114 : int
115 115 : _gpgme_io_write (int fd, const void *buffer, size_t count)
116 : {
117 : int nwritten;
118 115 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
119 : "buffer=%p, count=%u", buffer, count);
120 115 : TRACE_LOGBUF (buffer, count);
121 :
122 : do
123 : {
124 115 : nwritten = _gpgme_ath_write (fd, buffer, count);
125 : }
126 115 : while (nwritten == -1 && errno == EINTR);
127 :
128 115 : return TRACE_SYSRES (nwritten);
129 : }
130 :
131 :
132 : int
133 556 : _gpgme_io_pipe (int filedes[2], int inherit_idx)
134 : {
135 : int saved_errno;
136 : int err;
137 556 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_pipe", filedes,
138 : "inherit_idx=%i (GPGME uses it for %s)",
139 : inherit_idx, inherit_idx ? "reading" : "writing");
140 :
141 556 : err = pipe (filedes);
142 556 : if (err < 0)
143 0 : return TRACE_SYSRES (err);
144 :
145 : /* FIXME: Should get the old flags first. */
146 556 : err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
147 556 : saved_errno = errno;
148 556 : if (err < 0)
149 : {
150 0 : close (filedes[0]);
151 0 : close (filedes[1]);
152 : }
153 556 : errno = saved_errno;
154 556 : if (err)
155 0 : return TRACE_SYSRES (err);
156 :
157 556 : return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
158 : }
159 :
160 :
161 : int
162 1141 : _gpgme_io_close (int fd)
163 : {
164 : int res;
165 1141 : _gpgme_close_notify_handler_t handler = NULL;
166 : void *handler_value;
167 : int idx;
168 :
169 1141 : TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
170 :
171 1141 : if (fd == -1)
172 : {
173 0 : errno = EINVAL;
174 0 : return TRACE_SYSRES (-1);
175 : }
176 :
177 : /* First call the notify handler. */
178 1141 : LOCK (notify_table_lock);
179 10965 : for (idx=0; idx < notify_table_size; idx++)
180 : {
181 10547 : if (notify_table[idx].fd == fd)
182 : {
183 723 : handler = notify_table[idx].handler;
184 723 : handler_value = notify_table[idx].value;
185 723 : notify_table[idx].handler = NULL;
186 723 : notify_table[idx].value = NULL;
187 723 : notify_table[idx].fd = -1; /* Mark slot as free. */
188 723 : break;
189 : }
190 : }
191 1141 : UNLOCK (notify_table_lock);
192 1141 : if (handler)
193 : {
194 723 : TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
195 723 : handler (fd, handler_value);
196 : }
197 :
198 : /* Then do the close. */
199 1141 : res = close (fd);
200 1141 : return TRACE_SYSRES (res);
201 : }
202 :
203 :
204 : int
205 724 : _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
206 : void *value)
207 : {
208 724 : int res = 0;
209 : int idx;
210 :
211 724 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
212 : "close_handler=%p/%p", handler, value);
213 :
214 724 : assert (fd != -1);
215 :
216 724 : LOCK (notify_table_lock);
217 2916 : for (idx=0; idx < notify_table_size; idx++)
218 2889 : if (notify_table[idx].fd == -1)
219 697 : break;
220 724 : if (idx == notify_table_size)
221 : {
222 : /* We need to increase the size of the table. The approach we
223 : take is straightforward to minimize the risk of bugs. */
224 : notify_table_item_t newtbl;
225 27 : size_t newsize = notify_table_size + 64;
226 :
227 27 : newtbl = calloc (newsize, sizeof *newtbl);
228 27 : if (!newtbl)
229 : {
230 0 : res = -1;
231 0 : goto leave;
232 : }
233 27 : for (idx=0; idx < notify_table_size; idx++)
234 0 : newtbl[idx] = notify_table[idx];
235 1755 : for (; idx < newsize; idx++)
236 : {
237 1728 : newtbl[idx].fd = -1;
238 1728 : newtbl[idx].handler = NULL;
239 1728 : newtbl[idx].value = NULL;
240 : }
241 27 : free (notify_table);
242 27 : notify_table = newtbl;
243 27 : idx = notify_table_size;
244 27 : notify_table_size = newsize;
245 : }
246 724 : notify_table[idx].fd = fd;
247 724 : notify_table[idx].handler = handler;
248 724 : notify_table[idx].value = value;
249 :
250 : leave:
251 724 : UNLOCK (notify_table_lock);
252 :
253 724 : return TRACE_SYSRES (res);
254 : }
255 :
256 :
257 : int
258 84 : _gpgme_io_set_nonblocking (int fd)
259 : {
260 : int flags;
261 : int res;
262 84 : TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
263 :
264 84 : flags = fcntl (fd, F_GETFL, 0);
265 84 : if (flags == -1)
266 0 : return TRACE_SYSRES (-1);
267 84 : flags |= O_NONBLOCK;
268 84 : res = fcntl (fd, F_SETFL, flags);
269 84 : return TRACE_SYSRES (res);
270 : }
271 :
272 :
273 : static long int
274 325 : get_max_fds (void)
275 : {
276 325 : char *source = NULL;
277 325 : long int fds = -1;
278 : int rc;
279 :
280 : #ifdef RLIMIT_NOFILE
281 : {
282 : struct rlimit rl;
283 325 : rc = getrlimit (RLIMIT_NOFILE, &rl);
284 325 : if (rc == 0)
285 : {
286 325 : source = "RLIMIT_NOFILE";
287 325 : fds = rl.rlim_max;
288 : }
289 : }
290 : #endif
291 : #ifdef RLIMIT_OFILE
292 325 : if (fds == -1)
293 : {
294 : struct rlimit rl;
295 0 : rc = getrlimit (RLIMIT_OFILE, &rl);
296 0 : if (rc == 0)
297 : {
298 0 : source = "RLIMIT_OFILE";
299 0 : fds = rl.rlim_max;
300 : }
301 : }
302 : #endif
303 : #ifdef _SC_OPEN_MAX
304 325 : if (fds == -1)
305 : {
306 : long int scres;
307 0 : scres = sysconf (_SC_OPEN_MAX);
308 0 : if (scres >= 0)
309 : {
310 0 : source = "_SC_OPEN_MAX";
311 0 : return scres;
312 : }
313 : }
314 : #endif
315 : #ifdef OPEN_MAX
316 : if (fds == -1)
317 : {
318 : source = "OPEN_MAX";
319 : fds = OPEN_MAX;
320 : }
321 : #endif
322 :
323 : #if !defined(RLIMIT_NOFILE) && !defined(RLIMIT_OFILE) \
324 : && !defined(_SC_OPEN_MAX) && !defined(OPEN_MAX)
325 : #warning "No known way to get the maximum number of file descriptors."
326 : #endif
327 325 : if (fds == -1)
328 : {
329 0 : source = "arbitrary";
330 : /* Arbitrary limit. */
331 0 : fds = 1024;
332 : }
333 :
334 325 : TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
335 325 : return fds;
336 : }
337 :
338 :
339 : int
340 325 : _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
341 : {
342 : int status;
343 : pid_t ret;
344 :
345 325 : *r_status = 0;
346 325 : *r_signal = 0;
347 : do
348 325 : ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
349 324 : while (ret == (pid_t)(-1) && errno == EINTR);
350 :
351 324 : if (ret == pid)
352 : {
353 324 : if (WIFSIGNALED (status))
354 : {
355 0 : *r_status = 4; /* Need some value here. */
356 0 : *r_signal = WTERMSIG (status);
357 : }
358 324 : else if (WIFEXITED (status))
359 324 : *r_status = WEXITSTATUS (status);
360 : else
361 0 : *r_status = 4; /* Oops. */
362 324 : return 1;
363 : }
364 0 : return 0;
365 : }
366 :
367 :
368 : /* Returns 0 on success, -1 on error. */
369 : int
370 324 : _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
371 : struct spawn_fd_item_s *fd_list,
372 : void (*atfork) (void *opaque, int reserved),
373 : void *atforkvalue, pid_t *r_pid)
374 : {
375 : pid_t pid;
376 : int i;
377 : int status;
378 : int signo;
379 :
380 324 : TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
381 : "path=%s", path);
382 324 : i = 0;
383 4381 : while (argv[i])
384 : {
385 3733 : TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
386 3733 : i++;
387 : }
388 870 : for (i = 0; fd_list[i].fd != -1; i++)
389 546 : if (fd_list[i].dup_to == -1)
390 234 : TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
391 : else
392 312 : TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
393 :
394 324 : pid = fork ();
395 650 : if (pid == -1)
396 0 : return TRACE_SYSRES (-1);
397 :
398 650 : if (!pid)
399 : {
400 : /* Intermediate child to prevent zombie processes. */
401 325 : if ((pid = fork ()) == 0)
402 : {
403 325 : int max_fds = get_max_fds ();
404 : int fd;
405 :
406 : /* Child. */
407 325 : int seen_stdin = 0;
408 325 : int seen_stdout = 0;
409 325 : int seen_stderr = 0;
410 :
411 325 : if (atfork)
412 8 : atfork (atforkvalue, 0);
413 :
414 : /* First close all fds which will not be inherited. */
415 83200325 : for (fd = 0; fd < max_fds; fd++)
416 : {
417 223743094 : for (i = 0; fd_list[i].fd != -1; i++)
418 140543643 : if (fd_list[i].fd == fd)
419 549 : break;
420 83200000 : if (fd_list[i].fd == -1)
421 83199451 : close (fd);
422 : }
423 :
424 : /* And now dup and close those to be duplicated. */
425 874 : for (i = 0; fd_list[i].fd != -1; i++)
426 : {
427 : int child_fd;
428 : int res;
429 :
430 549 : if (fd_list[i].dup_to != -1)
431 313 : child_fd = fd_list[i].dup_to;
432 : else
433 236 : child_fd = fd_list[i].fd;
434 :
435 549 : if (child_fd == 0)
436 0 : seen_stdin = 1;
437 549 : else if (child_fd == 1)
438 313 : seen_stdout = 1;
439 236 : else if (child_fd == 2)
440 0 : seen_stderr = 1;
441 :
442 549 : if (fd_list[i].dup_to == -1)
443 236 : continue;
444 :
445 313 : res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
446 313 : if (res < 0)
447 : {
448 : #if 0
449 : /* FIXME: The debug file descriptor is not
450 : dup'ed anyway, so we can't see this. */
451 : TRACE_LOG1 ("dup2 failed in child: %s\n",
452 : strerror (errno));
453 : #endif
454 0 : _exit (8);
455 : }
456 :
457 313 : close (fd_list[i].fd);
458 : }
459 :
460 325 : if (! seen_stdin || ! seen_stdout || !seen_stderr)
461 : {
462 325 : fd = open ("/dev/null", O_RDWR);
463 325 : if (fd == -1)
464 : {
465 : /* The debug file descriptor is not dup'ed, so we
466 : can't do a trace output. */
467 0 : _exit (8);
468 : }
469 : /* Make sure that the process has connected stdin. */
470 325 : if (! seen_stdin && fd != 0)
471 : {
472 0 : if (dup2 (fd, 0) == -1)
473 0 : _exit (8);
474 : }
475 325 : if (! seen_stdout && fd != 1)
476 : {
477 12 : if (dup2 (fd, 1) == -1)
478 0 : _exit (8);
479 : }
480 325 : if (! seen_stderr && fd != 2)
481 : {
482 325 : if (dup2 (fd, 2) == -1)
483 0 : _exit (8);
484 : }
485 325 : if (fd != 0 && fd != 1 && fd != 2)
486 0 : close (fd);
487 : }
488 :
489 325 : execv (path, (char *const *) argv);
490 : /* Hmm: in that case we could write a special status code to the
491 : status-pipe. */
492 325 : _exit (8);
493 : /* End child. */
494 : }
495 0 : if (pid == -1)
496 0 : _exit (1);
497 : else
498 0 : _exit (0);
499 : }
500 :
501 325 : TRACE_LOG1 ("waiting for child process pid=%i", pid);
502 325 : _gpgme_io_waitpid (pid, 1, &status, &signo);
503 324 : if (status)
504 0 : return TRACE_SYSRES (-1);
505 :
506 869 : for (i = 0; fd_list[i].fd != -1; i++)
507 : {
508 545 : if (! (flags & IOSPAWN_FLAG_NOCLOSE))
509 537 : _gpgme_io_close (fd_list[i].fd);
510 : /* No handle translation. */
511 545 : fd_list[i].peer_name = fd_list[i].fd;
512 : }
513 :
514 324 : if (r_pid)
515 132 : *r_pid = pid;
516 :
517 324 : return TRACE_SYSRES (0);
518 : }
519 :
520 :
521 : /* Select on the list of fds. Returns: -1 = error, 0 = timeout or
522 : nothing to select, > 0 = number of signaled fds. */
523 : int
524 1826 : _gpgme_io_select (struct io_select_fd_s *fds, size_t nfds, int nonblock)
525 : {
526 : fd_set readfds;
527 : fd_set writefds;
528 : unsigned int i;
529 : int any;
530 : int max_fd;
531 : int n;
532 : int count;
533 : /* Use a 1s timeout. */
534 1826 : struct timeval timeout = { 1, 0 };
535 1826 : void *dbg_help = NULL;
536 1826 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
537 : "nfds=%u, nonblock=%u", nfds, nonblock);
538 :
539 1826 : FD_ZERO (&readfds);
540 1826 : FD_ZERO (&writefds);
541 1826 : max_fd = 0;
542 1826 : if (nonblock)
543 970 : timeout.tv_sec = 0;
544 :
545 1826 : TRACE_SEQ (dbg_help, "select on [ ");
546 :
547 1826 : any = 0;
548 11356 : for (i = 0; i < nfds; i++)
549 : {
550 9530 : if (fds[i].fd == -1)
551 6827 : continue;
552 2703 : if (fds[i].for_read)
553 : {
554 2332 : assert (!FD_ISSET (fds[i].fd, &readfds));
555 2332 : FD_SET (fds[i].fd, &readfds);
556 2332 : if (fds[i].fd > max_fd)
557 2306 : max_fd = fds[i].fd;
558 2332 : TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
559 2332 : any = 1;
560 : }
561 371 : else if (fds[i].for_write)
562 : {
563 371 : assert (!FD_ISSET (fds[i].fd, &writefds));
564 371 : FD_SET (fds[i].fd, &writefds);
565 371 : if (fds[i].fd > max_fd)
566 356 : max_fd = fds[i].fd;
567 371 : TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
568 371 : any = 1;
569 : }
570 2703 : fds[i].signaled = 0;
571 : }
572 1826 : TRACE_END (dbg_help, "]");
573 1826 : if (!any)
574 51 : return TRACE_SYSRES (0);
575 :
576 : do
577 : {
578 1775 : count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
579 : &timeout);
580 : }
581 1775 : while (count < 0 && errno == EINTR);
582 1775 : if (count < 0)
583 0 : return TRACE_SYSRES (-1);
584 :
585 1775 : TRACE_SEQ (dbg_help, "select OK [ ");
586 1775 : if (TRACE_ENABLED (dbg_help))
587 : {
588 0 : for (i = 0; i <= max_fd; i++)
589 : {
590 0 : if (FD_ISSET (i, &readfds))
591 0 : TRACE_ADD1 (dbg_help, "r0x%x ", i);
592 0 : if (FD_ISSET (i, &writefds))
593 0 : TRACE_ADD1 (dbg_help, "w0x%x ", i);
594 : }
595 0 : TRACE_END (dbg_help, "]");
596 : }
597 :
598 : /* The variable N is used to optimize it a little bit. */
599 4176 : for (n = count, i = 0; i < nfds && n; i++)
600 : {
601 2401 : if (fds[i].fd == -1)
602 : ;
603 2369 : else if (fds[i].for_read)
604 : {
605 2001 : if (FD_ISSET (fds[i].fd, &readfds))
606 : {
607 1564 : fds[i].signaled = 1;
608 1564 : n--;
609 : }
610 : }
611 368 : else if (fds[i].for_write)
612 : {
613 368 : if (FD_ISSET (fds[i].fd, &writefds))
614 : {
615 368 : fds[i].signaled = 1;
616 368 : n--;
617 : }
618 : }
619 : }
620 1775 : return TRACE_SYSRES (count);
621 : }
622 :
623 :
624 : int
625 125 : _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
626 : {
627 : int nread;
628 : int saved_errno;
629 : struct iovec *iov;
630 125 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
631 : "msg=%p, flags=%i", msg, flags);
632 :
633 125 : nread = 0;
634 125 : iov = msg->msg_iov;
635 375 : while (iov < msg->msg_iov + msg->msg_iovlen)
636 : {
637 125 : nread += iov->iov_len;
638 125 : iov++;
639 : }
640 :
641 125 : TRACE_LOG1 ("about to receive %d bytes", nread);
642 :
643 : do
644 : {
645 125 : nread = _gpgme_ath_recvmsg (fd, msg, flags);
646 : }
647 125 : while (nread == -1 && errno == EINTR);
648 125 : saved_errno = errno;
649 125 : if (nread > 0)
650 : {
651 125 : int nr = nread;
652 :
653 125 : iov = msg->msg_iov;
654 375 : while (nr > 0)
655 : {
656 125 : int len = nr > iov->iov_len ? iov->iov_len : nr;
657 125 : TRACE_LOGBUF (msg->msg_iov->iov_base, len);
658 125 : iov++;
659 125 : nr -= len;
660 : }
661 : }
662 125 : errno = saved_errno;
663 125 : return TRACE_SYSRES (nread);
664 : }
665 :
666 :
667 : int
668 240 : _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
669 : {
670 : int nwritten;
671 : struct iovec *iov;
672 240 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
673 : "msg=%p, flags=%i", msg, flags);
674 :
675 240 : nwritten = 0;
676 240 : iov = msg->msg_iov;
677 720 : while (iov < msg->msg_iov + msg->msg_iovlen)
678 : {
679 240 : nwritten += iov->iov_len;
680 240 : iov++;
681 : }
682 :
683 240 : TRACE_LOG1 ("about to receive %d bytes", nwritten);
684 240 : iov = msg->msg_iov;
685 720 : while (nwritten > 0)
686 : {
687 240 : int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
688 240 : TRACE_LOGBUF (msg->msg_iov->iov_base, len);
689 240 : iov++;
690 240 : nwritten -= len;
691 : }
692 :
693 : do
694 : {
695 240 : nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
696 : }
697 240 : while (nwritten == -1 && errno == EINTR);
698 240 : return TRACE_SYSRES (nwritten);
699 : }
700 :
701 :
702 : int
703 14 : _gpgme_io_dup (int fd)
704 : {
705 : int new_fd;
706 :
707 : do
708 14 : new_fd = dup (fd);
709 14 : while (new_fd == -1 && errno == EINTR);
710 :
711 14 : TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
712 :
713 14 : return new_fd;
714 : }
715 :
716 :
717 : int
718 0 : _gpgme_io_socket (int domain, int type, int proto)
719 : {
720 : int res;
721 :
722 0 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
723 : "type=%i, proto=%i", type, proto);
724 :
725 0 : res = socket (domain, type, proto);
726 :
727 0 : return TRACE_SYSRES (res);
728 : }
729 :
730 :
731 : int
732 0 : _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
733 : {
734 : int res;
735 :
736 0 : TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
737 : "addr=%p, addrlen=%i", addr, addrlen);
738 :
739 : do
740 0 : res = ath_connect (fd, addr, addrlen);
741 0 : while (res == -1 && errno == EINTR);
742 :
743 0 : return TRACE_SYSRES (res);
744 : }
|