c903072c6718a3d389980be376ca1e9d681834ef
[gpgme.git] / src / 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, 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 #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 \f
63 void
64 _gpgme_io_subsystem_init (void)
65 {
66   struct sigaction act;
67
68   sigaction (SIGPIPE, NULL, &act);
69   if (act.sa_handler == SIG_DFL)
70     {
71       act.sa_handler = SIG_IGN;
72       sigemptyset (&act.sa_mask);
73       act.sa_flags = 0;
74       sigaction (SIGPIPE, &act, NULL);
75     }
76 }
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 _gpgme_io_fd2str (char *buf, int buflen, int fd)
84 {
85   return snprintf (buf, buflen, "%d", fd);
86 }
87
88 \f
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 \f
105 int
106 _gpgme_io_read (int fd, void *buffer, size_t count)
107 {
108   int nread;
109   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
110               "buffer=%p, count=%u", buffer, count);
111
112   do
113     {
114       nread = _gpgme_ath_read (fd, buffer, count);
115     }
116   while (nread == -1 && errno == EINTR);
117
118   TRACE_LOGBUF (buffer, nread);
119   return TRACE_SYSRES (nread);
120 }
121
122
123 int
124 _gpgme_io_write (int fd, const void *buffer, size_t count)
125 {
126   int nwritten;
127   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
128               "buffer=%p, count=%u", buffer, count);
129   TRACE_LOGBUF (buffer, count);
130
131   do
132     {
133       nwritten = _gpgme_ath_write (fd, buffer, count);
134     }
135   while (nwritten == -1 && errno == EINTR);
136
137   return TRACE_SYSRES (nwritten);
138 }
139
140
141 int
142 _gpgme_io_pipe (int filedes[2], int inherit_idx)
143 {
144   int saved_errno;
145   int err;
146   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   err = pipe (filedes);
151   if (err < 0)
152     return TRACE_SYSRES (err);
153
154   /* FIXME: Should get the old flags first.  */
155   err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
156   saved_errno = errno;
157   if (err < 0)
158     {
159       close (filedes[0]);
160       close (filedes[1]);
161     }
162   errno = saved_errno;
163   if (err)
164     return TRACE_SYSRES (err);
165
166   return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
167 }
168
169
170 int
171 _gpgme_io_close (int fd)
172 {
173   int res;
174   _gpgme_close_notify_handler_t handler = NULL;
175   void *handler_value;
176   int idx;
177
178   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
179
180   if (fd == -1)
181     {
182       errno = EINVAL;
183       return TRACE_SYSRES (-1);
184     }
185
186   /* First call the notify handler.  */
187   LOCK (notify_table_lock);
188   for (idx=0; idx < notify_table_size; idx++)
189     {
190       if (notify_table[idx].fd == fd)
191         {
192           handler       = notify_table[idx].handler;
193           handler_value = notify_table[idx].value;
194           notify_table[idx].handler = NULL;
195           notify_table[idx].value = NULL;
196           notify_table[idx].fd = -1; /* Mark slot as free.  */
197           break;
198         }
199     }
200   UNLOCK (notify_table_lock);
201   if (handler)
202     {
203       TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
204       handler (fd, handler_value);
205     }
206
207   /* Then do the close.  */
208   res = close (fd);
209   return TRACE_SYSRES (res);
210 }
211
212
213 int
214 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
215                             void *value)
216 {
217   int res = 0;
218   int idx;
219
220   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
221               "close_handler=%p/%p", handler, value);
222
223   assert (fd != -1);
224
225   LOCK (notify_table_lock);
226   for (idx=0; idx < notify_table_size; idx++)
227     if (notify_table[idx].fd == -1)
228       break;
229   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       size_t newsize = notify_table_size + 64;
235
236       newtbl = calloc (newsize, sizeof *newtbl);
237       if (!newtbl)
238         {
239           res = -1;
240           goto leave;
241         }
242       for (idx=0; idx < notify_table_size; idx++)
243         newtbl[idx] = notify_table[idx];
244       for (; idx < newsize; idx++)
245         {
246           newtbl[idx].fd = -1;
247           newtbl[idx].handler = NULL;
248           newtbl[idx].value = NULL;
249         }
250       free (notify_table);
251       notify_table = newtbl;
252       idx = notify_table_size;
253       notify_table_size = newsize;
254     }
255   notify_table[idx].fd = fd;
256   notify_table[idx].handler = handler;
257   notify_table[idx].value = value;
258
259  leave:
260   UNLOCK (notify_table_lock);
261
262   return TRACE_SYSRES (res);
263 }
264
265
266 int
267 _gpgme_io_set_nonblocking (int fd)
268 {
269   int flags;
270   int res;
271   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
272
273   flags = fcntl (fd, F_GETFL, 0);
274   if (flags == -1)
275     return TRACE_SYSRES (-1);
276   flags |= O_NONBLOCK;
277   res = fcntl (fd, F_SETFL, flags);
278   return TRACE_SYSRES (res);
279 }
280
281
282 static long int
283 get_max_fds (void)
284 {
285   const char *source = NULL;
286   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     DIR *dir = NULL;
296     struct dirent *dir_entry;
297     const char *s;
298     int x;
299
300     dir = opendir ("/proc/self/fd");
301     if (dir)
302       {
303         while ((dir_entry = readdir (dir)))
304           {
305             s = dir_entry->d_name;
306             if ( *s < '0' || *s > '9')
307               continue;
308             x = atoi (s);
309             if (x > fds)
310               fds = x;
311           }
312         closedir (dir);
313       }
314     if (fds != -1)
315       {
316         fds++;
317         source = "/proc";
318       }
319     }
320 #endif /* __linux__ */
321
322 #ifdef RLIMIT_NOFILE
323   if (fds == -1)
324     {
325       struct rlimit rl;
326       rc = getrlimit (RLIMIT_NOFILE, &rl);
327       if (rc == 0)
328         {
329           source = "RLIMIT_NOFILE";
330           fds = rl.rlim_max;
331         }
332     }
333 #endif
334 #ifdef RLIMIT_OFILE
335   if (fds == -1)
336     {
337       struct rlimit rl;
338       rc = getrlimit (RLIMIT_OFILE, &rl);
339       if (rc == 0)
340         {
341           source = "RLIMIT_OFILE";
342           fds = rl.rlim_max;
343         }
344     }
345 #endif
346 #ifdef _SC_OPEN_MAX
347   if (fds == -1)
348     {
349       long int scres;
350       scres = sysconf (_SC_OPEN_MAX);
351       if (scres >= 0)
352         {
353           source = "_SC_OPEN_MAX";
354           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   if (fds == -1)
371     {
372       source = "arbitrary";
373       /* Arbitrary limit.  */
374       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   if (fds == INT32_MAX)
381     {
382       source = "aix-fix";
383       fds = 1024;
384     }
385 #endif
386
387   TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
388   return fds;
389 }
390
391
392 int
393 _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
394 {
395   int status;
396   pid_t ret;
397
398   *r_status = 0;
399   *r_signal = 0;
400   do
401     ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
402   while (ret == (pid_t)(-1) && errno == EINTR);
403
404   if (ret == pid)
405     {
406       if (WIFSIGNALED (status))
407         {
408           *r_status = 4; /* Need some value here.  */
409           *r_signal = WTERMSIG (status);
410         }
411       else if (WIFEXITED (status))
412         *r_status = WEXITSTATUS (status);
413       else
414         *r_status = 4; /* Oops.  */
415       return 1;
416     }
417   return 0;
418 }
419
420
421 /* Returns 0 on success, -1 on error.  */
422 int
423 _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   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
434               "path=%s", path);
435   i = 0;
436   while (argv[i])
437     {
438       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
439       i++;
440     }
441   for (i = 0; fd_list[i].fd != -1; i++)
442     if (fd_list[i].dup_to == -1)
443       TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
444     else
445       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
446
447   pid = fork ();
448   if (pid == -1)
449     return TRACE_SYSRES (-1);
450
451   if (!pid)
452     {
453       /* Intermediate child to prevent zombie processes.  */
454       if ((pid = fork ()) == 0)
455         {
456           int max_fds = get_max_fds ();
457           int fd;
458
459           /* Child.  */
460           int seen_stdin = 0;
461           int seen_stdout = 0;
462           int seen_stderr = 0;
463
464           if (atfork)
465             atfork (atforkvalue, 0);
466
467           /* First close all fds which will not be inherited.  */
468           for (fd = 0; fd < max_fds; fd++)
469             {
470               for (i = 0; fd_list[i].fd != -1; i++)
471                 if (fd_list[i].fd == fd)
472                   break;
473               if (fd_list[i].fd == -1)
474                 close (fd);
475             }
476
477           /* And now dup and close those to be duplicated.  */
478           for (i = 0; fd_list[i].fd != -1; i++)
479             {
480               int child_fd;
481               int res;
482
483               if (fd_list[i].dup_to != -1)
484                 child_fd = fd_list[i].dup_to;
485               else
486                 child_fd = fd_list[i].fd;
487
488               if (child_fd == 0)
489                 seen_stdin = 1;
490               else if (child_fd == 1)
491                 seen_stdout = 1;
492               else if (child_fd == 2)
493                 seen_stderr = 1;
494
495               if (fd_list[i].dup_to == -1)
496                 continue;
497
498               res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
499               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                   _exit (8);
508                 }
509
510               close (fd_list[i].fd);
511             }
512
513           if (! seen_stdin || ! seen_stdout || !seen_stderr)
514             {
515               fd = open ("/dev/null", O_RDWR);
516               if (fd == -1)
517                 {
518                   /* The debug file descriptor is not dup'ed, so we
519                      can't do a trace output.  */
520                   _exit (8);
521                 }
522               /* Make sure that the process has connected stdin.  */
523               if (! seen_stdin && fd != 0)
524                 {
525                   if (dup2 (fd, 0) == -1)
526                     _exit (8);
527                 }
528               if (! seen_stdout && fd != 1)
529                 {
530                   if (dup2 (fd, 1) == -1)
531                     _exit (8);
532                 }
533               if (! seen_stderr && fd != 2)
534                 {
535                   if (dup2 (fd, 2) == -1)
536                     _exit (8);
537                 }
538               if (fd != 0 && fd != 1 && fd != 2)
539                 close (fd);
540             }
541
542           execv (path, (char *const *) argv);
543           /* Hmm: in that case we could write a special status code to the
544              status-pipe.  */
545           _exit (8);
546           /* End child.  */
547         }
548       if (pid == -1)
549         _exit (1);
550       else
551         _exit (0);
552     }
553
554   TRACE_LOG1 ("waiting for child process pid=%i", pid);
555   _gpgme_io_waitpid (pid, 1, &status, &signo);
556   if (status)
557     return TRACE_SYSRES (-1);
558
559   for (i = 0; fd_list[i].fd != -1; i++)
560     {
561       if (! (flags & IOSPAWN_FLAG_NOCLOSE))
562         _gpgme_io_close (fd_list[i].fd);
563       /* No handle translation.  */
564       fd_list[i].peer_name = fd_list[i].fd;
565     }
566
567   if (r_pid)
568     *r_pid = pid;
569
570   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 _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   struct timeval timeout = { 1, 0 };
588   void *dbg_help = NULL;
589   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
590               "nfds=%u, nonblock=%u", nfds, nonblock);
591
592   FD_ZERO (&readfds);
593   FD_ZERO (&writefds);
594   max_fd = 0;
595   if (nonblock)
596     timeout.tv_sec = 0;
597
598   TRACE_SEQ (dbg_help, "select on [ ");
599
600   any = 0;
601   for (i = 0; i < nfds; i++)
602     {
603       if (fds[i].fd == -1)
604         continue;
605       if (fds[i].for_read)
606         {
607           if (fds[i].fd >= FD_SETSIZE)
608             {
609               TRACE_END (dbg_help, " -BAD- ]");
610               gpg_err_set_errno (EMFILE);
611               return TRACE_SYSRES (-1);
612             }
613           assert (!FD_ISSET (fds[i].fd, &readfds));
614           FD_SET (fds[i].fd, &readfds);
615           if (fds[i].fd > max_fd)
616             max_fd = fds[i].fd;
617           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
618           any = 1;
619         }
620       else if (fds[i].for_write)
621         {
622           if (fds[i].fd >= FD_SETSIZE)
623             {
624               TRACE_END (dbg_help, " -BAD- ]");
625               gpg_err_set_errno (EMFILE);
626               return TRACE_SYSRES (-1);
627             }
628           assert (!FD_ISSET (fds[i].fd, &writefds));
629           FD_SET (fds[i].fd, &writefds);
630           if (fds[i].fd > max_fd)
631             max_fd = fds[i].fd;
632           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
633           any = 1;
634         }
635       fds[i].signaled = 0;
636     }
637   TRACE_END (dbg_help, "]");
638   if (!any)
639     return TRACE_SYSRES (0);
640
641   do
642     {
643       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
644                                  &timeout);
645     }
646   while (count < 0 && errno == EINTR);
647   if (count < 0)
648     return TRACE_SYSRES (-1);
649
650   TRACE_SEQ (dbg_help, "select OK [ ");
651   if (TRACE_ENABLED (dbg_help))
652     {
653       for (i = 0; i <= max_fd; i++)
654         {
655           if (FD_ISSET (i, &readfds))
656             TRACE_ADD1 (dbg_help, "r0x%x ", i);
657           if (FD_ISSET (i, &writefds))
658             TRACE_ADD1 (dbg_help, "w0x%x ", i);
659         }
660       TRACE_END (dbg_help, "]");
661     }
662
663   /* The variable N is used to optimize it a little bit.  */
664   for (n = count, i = 0; i < nfds && n; i++)
665     {
666       if (fds[i].fd == -1)
667         ;
668       else if (fds[i].for_read)
669         {
670           if (FD_ISSET (fds[i].fd, &readfds))
671             {
672               fds[i].signaled = 1;
673               n--;
674             }
675         }
676       else if (fds[i].for_write)
677         {
678           if (FD_ISSET (fds[i].fd, &writefds))
679             {
680               fds[i].signaled = 1;
681               n--;
682             }
683         }
684     }
685   return TRACE_SYSRES (count);
686 }
687
688 \f
689 int
690 _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
691 {
692   int nread;
693   int saved_errno;
694   struct iovec *iov;
695   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
696               "msg=%p, flags=%i", msg, flags);
697
698   nread = 0;
699   iov = msg->msg_iov;
700   while (iov < msg->msg_iov + msg->msg_iovlen)
701     {
702       nread += iov->iov_len;
703       iov++;
704     }
705
706   TRACE_LOG1 ("about to receive %d bytes", nread);
707
708   do
709     {
710       nread = _gpgme_ath_recvmsg (fd, msg, flags);
711     }
712   while (nread == -1 && errno == EINTR);
713   saved_errno = errno;
714   if (nread > 0)
715     {
716       int nr = nread;
717
718       iov = msg->msg_iov;
719       while (nr > 0)
720         {
721           int len = nr > iov->iov_len ? iov->iov_len : nr;
722           TRACE_LOGBUF (msg->msg_iov->iov_base, len);
723           iov++;
724           nr -= len;
725         }
726     }
727   errno = saved_errno;
728   return TRACE_SYSRES (nread);
729 }
730
731
732 int
733 _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
734 {
735   int nwritten;
736   struct iovec *iov;
737   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
738               "msg=%p, flags=%i", msg, flags);
739
740   nwritten = 0;
741   iov = msg->msg_iov;
742   while (iov < msg->msg_iov + msg->msg_iovlen)
743     {
744       nwritten += iov->iov_len;
745       iov++;
746     }
747
748   TRACE_LOG1 ("about to receive %d bytes", nwritten);
749   iov = msg->msg_iov;
750   while (nwritten > 0)
751     {
752       int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
753       TRACE_LOGBUF (msg->msg_iov->iov_base, len);
754       iov++;
755       nwritten -= len;
756     }
757
758   do
759     {
760       nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
761     }
762   while (nwritten == -1 && errno == EINTR);
763   return TRACE_SYSRES (nwritten);
764 }
765
766
767 int
768 _gpgme_io_dup (int fd)
769 {
770   int new_fd;
771
772   do
773     new_fd = dup (fd);
774   while (new_fd == -1 && errno == EINTR);
775
776   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
777
778   return new_fd;
779 }
780
781 \f
782 int
783 _gpgme_io_socket (int domain, int type, int proto)
784 {
785   int res;
786
787   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
788               "type=%i, proto=%i", type, proto);
789
790   res = socket (domain, type, proto);
791
792   return TRACE_SYSRES (res);
793 }
794
795
796 int
797 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
798 {
799   int res;
800
801   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
802               "addr=%p, addrlen=%i", addr, addrlen);
803
804   do
805     res = ath_connect (fd, addr, addrlen);
806   while (res == -1 && errno == EINTR);
807
808   return TRACE_SYSRES (res);
809 }