Fix possible zombie processes.
[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 #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 \f
54 void
55 _gpgme_io_subsystem_init (void)
56 {
57   struct sigaction act;
58
59   sigaction (SIGPIPE, NULL, &act);
60   if (act.sa_handler == SIG_DFL)
61     {
62       act.sa_handler = SIG_IGN;
63       sigemptyset (&act.sa_mask);
64       act.sa_flags = 0;
65       sigaction (SIGPIPE, &act, NULL);
66     }
67 }
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 _gpgme_io_fd2str (char *buf, int buflen, int fd)
75 {
76   return snprintf (buf, buflen, "%d", fd);
77 }
78
79 \f
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 \f
96 int
97 _gpgme_io_read (int fd, void *buffer, size_t count)
98 {
99   int nread;
100   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_read", fd,
101               "buffer=%p, count=%u", buffer, count);
102
103   do
104     {
105       nread = _gpgme_ath_read (fd, buffer, count);
106     }
107   while (nread == -1 && errno == EINTR);
108
109   TRACE_LOGBUF (buffer, nread);
110   return TRACE_SYSRES (nread);
111 }
112
113
114 int
115 _gpgme_io_write (int fd, const void *buffer, size_t count)
116 {
117   int nwritten;
118   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_write", fd,
119               "buffer=%p, count=%u", buffer, count);
120   TRACE_LOGBUF (buffer, count);
121
122   do
123     {
124       nwritten = _gpgme_ath_write (fd, buffer, count);
125     }
126   while (nwritten == -1 && errno == EINTR);
127
128   return TRACE_SYSRES (nwritten);
129 }
130
131
132 int
133 _gpgme_io_pipe (int filedes[2], int inherit_idx)
134 {
135   int saved_errno;
136   int err;
137   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   err = pipe (filedes);
142   if (err < 0)
143     return TRACE_SYSRES (err);
144
145   /* FIXME: Should get the old flags first.  */
146   err = fcntl (filedes[1 - inherit_idx], F_SETFD, FD_CLOEXEC);
147   saved_errno = errno;
148   if (err < 0)
149     {
150       close (filedes[0]);
151       close (filedes[1]);
152     }
153   errno = saved_errno;
154   if (err)
155     return TRACE_SYSRES (err);
156
157   return TRACE_SUC2 ("read=0x%x, write=0x%x", filedes[0], filedes[1]);
158 }
159
160
161 int
162 _gpgme_io_close (int fd)
163 {
164   int res;
165   _gpgme_close_notify_handler_t handler = NULL;
166   void *handler_value;
167   int idx;
168
169   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_close", fd);
170
171   if (fd == -1)
172     {
173       errno = EINVAL;
174       return TRACE_SYSRES (-1);
175     }
176
177   /* First call the notify handler.  */
178   LOCK (notify_table_lock);
179   for (idx=0; idx < notify_table_size; idx++)
180     {
181       if (notify_table[idx].fd == fd)
182         {
183           handler       = notify_table[idx].handler;
184           handler_value = notify_table[idx].value;
185           notify_table[idx].handler = NULL;
186           notify_table[idx].value = NULL;
187           notify_table[idx].fd = -1; /* Mark slot as free.  */
188           break;
189         }
190     }
191   UNLOCK (notify_table_lock);
192   if (handler)
193     {
194       TRACE_LOG2 ("invoking close handler %p/%p", handler, handler_value);
195       handler (fd, handler_value);
196     }
197
198   /* Then do the close.  */
199   res = close (fd);
200   return TRACE_SYSRES (res);
201 }
202
203
204 int
205 _gpgme_io_set_close_notify (int fd, _gpgme_close_notify_handler_t handler,
206                             void *value)
207 {
208   int res = 0;
209   int idx;
210
211   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_set_close_notify", fd,
212               "close_handler=%p/%p", handler, value);
213
214   assert (fd != -1);
215
216   LOCK (notify_table_lock);
217   for (idx=0; idx < notify_table_size; idx++)
218     if (notify_table[idx].fd == -1)
219       break;
220   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       size_t newsize = notify_table_size + 64;
226
227       newtbl = calloc (newsize, sizeof *newtbl);
228       if (!newtbl)
229         {
230           res = -1;
231           goto leave;
232         }
233       for (idx=0; idx < notify_table_size; idx++)
234         newtbl[idx] = notify_table[idx];
235       for (; idx < newsize; idx++)
236         {
237           newtbl[idx].fd = -1;
238           newtbl[idx].handler = NULL;
239           newtbl[idx].value = NULL;
240         }
241       free (notify_table);
242       notify_table = newtbl;
243       idx = notify_table_size;
244       notify_table_size = newsize;
245     }
246   notify_table[idx].fd = fd;
247   notify_table[idx].handler = handler;
248   notify_table[idx].value = value;
249
250  leave:
251   UNLOCK (notify_table_lock);
252
253   return TRACE_SYSRES (res);
254 }
255
256
257 int
258 _gpgme_io_set_nonblocking (int fd)
259 {
260   int flags;
261   int res;
262   TRACE_BEG (DEBUG_SYSIO, "_gpgme_io_set_nonblocking", fd);
263
264   flags = fcntl (fd, F_GETFL, 0);
265   if (flags == -1)
266     return TRACE_SYSRES (-1);
267   flags |= O_NONBLOCK;
268   res = fcntl (fd, F_SETFL, flags);
269   return TRACE_SYSRES (res);
270 }
271
272
273 static long int
274 get_max_fds (void)
275 {
276   char *source = NULL;
277   long int fds = -1;
278   int rc;
279
280 #ifdef RLIMIT_NOFILE
281   {
282     struct rlimit rl;
283     rc = getrlimit (RLIMIT_NOFILE, &rl);
284     if (rc == 0)
285       {
286         source = "RLIMIT_NOFILE";
287         fds = rl.rlim_max;
288       }
289   }
290 #endif
291 #ifdef RLIMIT_OFILE
292   if (fds == -1)
293     {
294       struct rlimit rl;
295       rc = getrlimit (RLIMIT_OFILE, &rl);
296       if (rc == 0)
297         {
298           source = "RLIMIT_OFILE";
299           fds = rl.rlim_max;
300         }
301     }
302 #endif
303 #ifdef _SC_OPEN_MAX
304   if (fds == -1)
305     {
306       long int scres;
307       scres = sysconf (_SC_OPEN_MAX);
308       if (scres >= 0)
309         {
310           source = "_SC_OPEN_MAX";
311           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   if (fds == -1)
328     {
329       source = "arbitrary";
330       /* Arbitrary limit.  */
331       fds = 1024;
332     }
333
334   TRACE2 (DEBUG_SYSIO, "gpgme:max_fds", 0, "max fds=%i (%s)", fds, source);
335   return fds;
336 }
337
338
339 int
340 _gpgme_io_waitpid (int pid, int hang, int *r_status, int *r_signal)
341 {
342   int status;
343   pid_t ret;
344
345   *r_status = 0;
346   *r_signal = 0;
347   do
348     ret = _gpgme_ath_waitpid (pid, &status, hang? 0 : WNOHANG);
349   while (ret == (pid_t)(-1) && errno == EINTR);
350
351   if (ret == pid)
352     {
353       if (WIFSIGNALED (status))
354         {
355           *r_status = 4; /* Need some value here.  */
356           *r_signal = WTERMSIG (status);
357         }
358       else if (WIFEXITED (status))
359         *r_status = WEXITSTATUS (status);
360       else
361         *r_status = 4; /* Oops.  */
362       return 1;
363     }
364   return 0;
365 }
366
367
368 /* Returns 0 on success, -1 on error.  */
369 int
370 _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   TRACE_BEG1 (DEBUG_SYSIO, "_gpgme_io_spawn", path,
381               "path=%s", path);
382   i = 0;
383   while (argv[i])
384     {
385       TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
386       i++;
387     }
388   for (i = 0; fd_list[i].fd != -1; i++)
389     if (fd_list[i].dup_to == -1)
390       TRACE_LOG2 ("fd[%i] = 0x%x", i, fd_list[i].fd);
391     else
392       TRACE_LOG3 ("fd[%i] = 0x%x -> 0x%x", i, fd_list[i].fd, fd_list[i].dup_to);
393
394   pid = fork ();
395   if (pid == -1)
396     return TRACE_SYSRES (-1);
397
398   if (!pid)
399     {
400       /* Intermediate child to prevent zombie processes.  */
401       if ((pid = fork ()) == 0)
402         {
403           int max_fds = get_max_fds ();
404           int fd;
405
406           /* Child.  */
407           int seen_stdin = 0;
408           int seen_stdout = 0;
409           int seen_stderr = 0;
410
411           if (atfork)
412             atfork (atforkvalue, 0);
413
414           /* First close all fds which will not be inherited.  */
415           for (fd = 0; fd < max_fds; fd++)
416             {
417               for (i = 0; fd_list[i].fd != -1; i++)
418                 if (fd_list[i].fd == fd)
419                   break;
420               if (fd_list[i].fd == -1)
421                 close (fd);
422             }
423
424           /* And now dup and close those to be duplicated.  */
425           for (i = 0; fd_list[i].fd != -1; i++)
426             {
427               int child_fd;
428               int res;
429
430               if (fd_list[i].dup_to != -1)
431                 child_fd = fd_list[i].dup_to;
432               else
433                 child_fd = fd_list[i].fd;
434
435               if (child_fd == 0)
436                 seen_stdin = 1;
437               else if (child_fd == 1)
438                 seen_stdout = 1;
439               else if (child_fd == 2)
440                 seen_stderr = 1;
441
442               if (fd_list[i].dup_to == -1)
443                 continue;
444
445               res = dup2 (fd_list[i].fd, fd_list[i].dup_to);
446               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                   _exit (8);
455                 }
456
457               close (fd_list[i].fd);
458             }
459
460           if (! seen_stdin || ! seen_stdout || !seen_stderr)
461             {
462               fd = open ("/dev/null", O_RDWR);
463               if (fd == -1)
464                 {
465                   /* The debug file descriptor is not dup'ed, so we
466                      can't do a trace output.  */
467                   _exit (8);
468                 }
469               /* Make sure that the process has connected stdin.  */
470               if (! seen_stdin && fd != 0)
471                 {
472                   if (dup2 (fd, 0) == -1)
473                     _exit (8);
474                 }
475               if (! seen_stdout && fd != 1)
476                 {
477                   if (dup2 (fd, 1) == -1)
478                     _exit (8);
479                 }
480               if (! seen_stderr && fd != 2)
481                 {
482                   if (dup2 (fd, 2) == -1)
483                     _exit (8);
484                 }
485               if (fd != 0 && fd != 1 && fd != 2)
486                 close (fd);
487             }
488
489           execv (path, (char *const *) argv);
490           /* Hmm: in that case we could write a special status code to the
491              status-pipe.  */
492           _exit (8);
493           /* End child.  */
494         }
495       if (pid == -1)
496         _exit (1);
497       else
498         _exit (0);
499     }
500
501   TRACE_LOG1 ("waiting for child process pid=%i", pid);
502   _gpgme_io_waitpid (pid, 1, &status, &signo);
503   if (status)
504     return TRACE_SYSRES (-1);
505
506   for (i = 0; fd_list[i].fd != -1; i++)
507     {
508       if (! (flags & IOSPAWN_FLAG_NOCLOSE))
509         _gpgme_io_close (fd_list[i].fd);
510       /* No handle translation.  */
511       fd_list[i].peer_name = fd_list[i].fd;
512     }
513
514   if (r_pid)
515     *r_pid = pid;
516
517   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 _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   struct timeval timeout = { 1, 0 };
535   void *dbg_help = NULL;
536   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_select", fds,
537               "nfds=%u, nonblock=%u", nfds, nonblock);
538
539   FD_ZERO (&readfds);
540   FD_ZERO (&writefds);
541   max_fd = 0;
542   if (nonblock)
543     timeout.tv_sec = 0;
544
545   TRACE_SEQ (dbg_help, "select on [ ");
546
547   any = 0;
548   for (i = 0; i < nfds; i++)
549     {
550       if (fds[i].fd == -1)
551         continue;
552       if (fds[i].for_read)
553         {
554           assert (!FD_ISSET (fds[i].fd, &readfds));
555           FD_SET (fds[i].fd, &readfds);
556           if (fds[i].fd > max_fd)
557             max_fd = fds[i].fd;
558           TRACE_ADD1 (dbg_help, "r0x%x ", fds[i].fd);
559           any = 1;
560         }
561       else if (fds[i].for_write)
562         {
563           assert (!FD_ISSET (fds[i].fd, &writefds));
564           FD_SET (fds[i].fd, &writefds);
565           if (fds[i].fd > max_fd)
566             max_fd = fds[i].fd;
567           TRACE_ADD1 (dbg_help, "w0x%x ", fds[i].fd);
568           any = 1;
569         }
570       fds[i].signaled = 0;
571     }
572   TRACE_END (dbg_help, "]");
573   if (!any)
574     return TRACE_SYSRES (0);
575
576   do
577     {
578       count = _gpgme_ath_select (max_fd + 1, &readfds, &writefds, NULL,
579                                  &timeout);
580     }
581   while (count < 0 && errno == EINTR);
582   if (count < 0)
583     return TRACE_SYSRES (-1);
584
585   TRACE_SEQ (dbg_help, "select OK [ ");
586   if (TRACE_ENABLED (dbg_help))
587     {
588       for (i = 0; i <= max_fd; i++)
589         {
590           if (FD_ISSET (i, &readfds))
591             TRACE_ADD1 (dbg_help, "r0x%x ", i);
592           if (FD_ISSET (i, &writefds))
593             TRACE_ADD1 (dbg_help, "w0x%x ", i);
594         }
595       TRACE_END (dbg_help, "]");
596     }
597
598   /* The variable N is used to optimize it a little bit.  */
599   for (n = count, i = 0; i < nfds && n; i++)
600     {
601       if (fds[i].fd == -1)
602         ;
603       else if (fds[i].for_read)
604         {
605           if (FD_ISSET (fds[i].fd, &readfds))
606             {
607               fds[i].signaled = 1;
608               n--;
609             }
610         }
611       else if (fds[i].for_write)
612         {
613           if (FD_ISSET (fds[i].fd, &writefds))
614             {
615               fds[i].signaled = 1;
616               n--;
617             }
618         }
619     }
620   return TRACE_SYSRES (count);
621 }
622
623 \f
624 int
625 _gpgme_io_recvmsg (int fd, struct msghdr *msg, int flags)
626 {
627   int nread;
628   int saved_errno;
629   struct iovec *iov;
630   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_recvmsg", fd,
631               "msg=%p, flags=%i", msg, flags);
632
633   nread = 0;
634   iov = msg->msg_iov;
635   while (iov < msg->msg_iov + msg->msg_iovlen)
636     {
637       nread += iov->iov_len;
638       iov++;
639     }
640
641   TRACE_LOG1 ("about to receive %d bytes", nread);
642
643   do
644     {
645       nread = _gpgme_ath_recvmsg (fd, msg, flags);
646     }
647   while (nread == -1 && errno == EINTR);
648   saved_errno = errno;
649   if (nread > 0)
650     {
651       int nr = nread;
652
653       iov = msg->msg_iov;
654       while (nr > 0)
655         {
656           int len = nr > iov->iov_len ? iov->iov_len : nr;
657           TRACE_LOGBUF (msg->msg_iov->iov_base, len);
658           iov++;
659           nr -= len;
660         }
661     }
662   errno = saved_errno;
663   return TRACE_SYSRES (nread);
664 }
665
666
667 int
668 _gpgme_io_sendmsg (int fd, const struct msghdr *msg, int flags)
669 {
670   int nwritten;
671   struct iovec *iov;
672   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_sendmsg", fd,
673               "msg=%p, flags=%i", msg, flags);
674
675   nwritten = 0;
676   iov = msg->msg_iov;
677   while (iov < msg->msg_iov + msg->msg_iovlen)
678     {
679       nwritten += iov->iov_len;
680       iov++;
681     }
682
683   TRACE_LOG1 ("about to receive %d bytes", nwritten);
684   iov = msg->msg_iov;
685   while (nwritten > 0)
686     {
687       int len = nwritten > iov->iov_len ? iov->iov_len : nwritten;
688       TRACE_LOGBUF (msg->msg_iov->iov_base, len);
689       iov++;
690       nwritten -= len;
691     }
692
693   do
694     {
695       nwritten = _gpgme_ath_sendmsg (fd, msg, flags);
696     }
697   while (nwritten == -1 && errno == EINTR);
698   return TRACE_SYSRES (nwritten);
699 }
700
701
702 int
703 _gpgme_io_dup (int fd)
704 {
705   int new_fd;
706
707   do
708     new_fd = dup (fd);
709   while (new_fd == -1 && errno == EINTR);
710
711   TRACE1 (DEBUG_SYSIO, "_gpgme_io_dup", fd, "new fd==%i", new_fd);
712
713   return new_fd;
714 }
715
716 \f
717 int
718 _gpgme_io_socket (int domain, int type, int proto)
719 {
720   int res;
721
722   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_socket", domain,
723               "type=%i, proto=%i", type, proto);
724
725   res = socket (domain, type, proto);
726
727   return TRACE_SYSRES (res);
728 }
729
730
731 int
732 _gpgme_io_connect (int fd, struct sockaddr *addr, int addrlen)
733 {
734   int res;
735
736   TRACE_BEG2 (DEBUG_SYSIO, "_gpgme_io_connect", fd,
737               "addr=%p, addrlen=%i", addr, addrlen);
738
739   do
740     res = ath_connect (fd, addr, addrlen);
741   while (res == -1 && errno == EINTR);
742
743   return TRACE_SYSRES (res);
744 }