f3361534d568a63c34007ece871ff3fc57cdee86
[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   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           assert (!FD_ISSET (fds[i].fd, &readfds));
608           FD_SET (fds[i].fd, &readfds);
609           if (fds[i].fd > max_fd)
610             max_fd = fds[i].fd;
611           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
612           any = 1;
613         }
614       else if (fds[i].for_write)
615         {
616           assert (!FD_ISSET (fds[i].fd, &writefds));
617           FD_SET (fds[i].fd, &writefds);
618           if (fds[i].fd > max_fd)
619             max_fd = fds[i].fd;
620           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
621           any = 1;
622         }
623       fds[i].signaled = 0;
624     }
625   TRACE_END (dbg_help, "]");
626   if (!any)
627     return TRACE_SYSRES (0);
628
629   do
630     {
631       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
632                                  &timeout);
633     }
634   while (count < 0 && errno == EINTR);
635   if (count < 0)
636     return TRACE_SYSRES (-1);
637
638   TRACE_SEQ (dbg_help, "select OK [ ");
639   if (TRACE_ENABLED (dbg_help))
640     {
641       for (i = 0; i <= max_fd; i++)
642         {
643           if (FD_ISSET (i, &readfds))
644             TRACE_ADD1 (dbg_help, "r0x%x ", i);
645           if (FD_ISSET (i, &writefds))
646             TRACE_ADD1 (dbg_help, "w0x%x ", i);
647         }
648       TRACE_END (dbg_help, "]");
649     }
650
651   /* The variable N is used to optimize it a little bit.  */
652   for (n = count, i = 0; i < nfds && n; i++)
653     {
654       if (fds[i].fd == -1)
655         ;
656       else if (fds[i].for_read)
657         {
658           if (FD_ISSET (fds[i].fd, &readfds))
659             {
660               fds[i].signaled = 1;
661               n--;
662             }
663         }
664       else if (fds[i].for_write)
665         {
666           if (FD_ISSET (fds[i].fd, &writefds))
667             {
668               fds[i].signaled = 1;
669               n--;
670             }
671         }
672     }
673   return TRACE_SYSRES (count);
674 }
675
676 \f
677 int
678 _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
679 {
680   int nread;
681   int saved_errno;
682   struct iovec *iov;
683   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
684               "msg=%p, flags=%i", msg, flags);
685
686   nread = 0;
687   iov = msg->msg_iov;
688   while (iov < msg->msg_iov + msg->msg_iovlen)
689     {
690       nread += iov->iov_len;
691       iov++;
692     }
693
694   TRACE_LOG1 ("about to receive %d bytes", nread);
695
696   do
697     {
698       nread = _gpgme_ath_recvmsg (fd, msg, flags);
699     }
700   while (nread == -1 && errno == EINTR);
701   saved_errno = errno;
702   if (nread > 0)
703     {
704       int nr = nread;
705
706       iov = msg->msg_iov;
707       while (nr > 0)
708         {
709           int len = nr > iov->iov_len ? iov->iov_len : nr;
710           TRACE_LOGBUF (msg->msg_iov->iov_base, len);
711           iov++;
712           nr -= len;
713         }
714     }
715   errno = saved_errno;
716   return TRACE_SYSRES (nread);
717 }
718
719
720 int
721 _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
722 {
723   int nwritten;
724   struct iovec *iov;
725   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
726               "msg=%p, flags=%i", msg, flags);
727
728   nwritten = 0;
729   iov = msg->msg_iov;
730   while (iov < msg->msg_iov + msg->msg_iovlen)
731     {
732       nwritten += iov->iov_len;
733       iov++;
734     }
735
736   TRACE_LOG1 ("about to receive %d bytes", nwritten);
737   iov = msg->msg_iov;
738   while (nwritten > 0)
739     {
740       int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
741       TRACE_LOGBUF (msg->msg_iov->iov_base, len);
742       iov++;
743       nwritten -= len;
744     }
745
746   do
747     {
748       nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
749     }
750   while (nwritten == -1 && errno == EINTR);
751   return TRACE_SYSRES (nwritten);
752 }
753
754
755 int
756 _gpgme_io_dup (int fd)
757 {
758   int new_fd;
759
760   do
761     new_fd = dup (fd);
762   while (new_fd == -1 && errno == EINTR);
763
764   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
765
766   return new_fd;
767 }
768
769 \f
770 int
771 _gpgme_io_socket (int domain, int type, int proto)
772 {
773   int res;
774
775   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
776               "type=%i, proto=%i", type, proto);
777
778   res = socket (domain, type, proto);
779
780   return TRACE_SYSRES (res);
781 }
782
783
784 int
785 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
786 {
787   int res;
788
789   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
790               "addr=%p, addrlen=%i", addr, addrlen);
791
792   do
793     res = ath_connect (fd, addr, addrlen);
794   while (res == -1 && errno == EINTR);
795
796   return TRACE_SYSRES (res);
797 }