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